Fixes #46 by allowing :host :none
Also adds `:dbname-separator` and `:host-prefix` for fine-grained control over the JDBC URL format.
This commit is contained in:
parent
e361f875c1
commit
44dba4f29c
6 changed files with 86 additions and 16 deletions
|
|
@ -6,6 +6,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.1 release:
|
The following changes have been committed to the **master** branch since the 1.0.1 release:
|
||||||
|
|
||||||
|
* Fix #46 by allowing `:host` to be `:none` so `next.jdbc` will omit the host/port section of the JDBC URL, so that local databases can be used with `:dbtype`/`:classname` for database types that `next.jdbc` does not know. Also adds `dbname-separator` and `:host-prefix` to the "db-spec" to allow fine-grained control over how the JDBC URL is assembled.
|
||||||
* Fix #45 by adding [TimesTen](https://www.oracle.com/database/technologies/related/timesten.html) driver support.
|
* Fix #45 by adding [TimesTen](https://www.oracle.com/database/technologies/related/timesten.html) driver support.
|
||||||
* Fix #44 so that `insert-multi!` with an empty `rows` vector returns `[]`.
|
* Fix #44 so that `insert-multi!` with an empty `rows` vector returns `[]`.
|
||||||
* Fix #43 by adjusting the spec for `insert-multi!` to "require less" of the `cols` and `rows` arguments.
|
* Fix #43 by adjusting the spec for `insert-multi!` to "require less" of the `cols` and `rows` arguments.
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ Although `get-datasource` does not accept options, the "db spec" hash map passed
|
||||||
|
|
||||||
* `:dbtype` -- a string that identifies the type of JDBC database being used,
|
* `:dbtype` -- a string that identifies the type of JDBC database being used,
|
||||||
* `:dbname` -- a string that identifies the name of the actual database being used,
|
* `:dbname` -- a string that identifies the name of the actual database being used,
|
||||||
|
* `:dbname-separator` -- an optional string that can be used to override the `/` or `:` that is normally placed in front of the database name in the JDBC URL,
|
||||||
* `:host` -- an optional string that identifies the IP address or hostname of the server on which the database is running; the default is `"127.0.0.1"`,
|
* `:host` -- an optional string that identifies the IP address or hostname of the server on which the database is running; the default is `"127.0.0.1"`,
|
||||||
|
* `:host-prefix` -- an optional string that can be used to override the `//` that is normally placed in front of the IP address or hostname in the JDBC URL,
|
||||||
* `:port` -- an optional integer that identifies the port on which the database is running; for common database types, `next.jdbc` knows the default so this should only be needed for non-standard setups or "exotic" database types,
|
* `:port` -- an optional integer that identifies the port on which the database is running; for common database types, `next.jdbc` knows the default so this should only be needed for non-standard setups or "exotic" database types,
|
||||||
* `:classname` -- an optional string that identifies the name of the JDBC driver class to be used for the connection; for common database types, `next.jdbc` knows the default so this should only be needed for "exotic" database types,
|
* `:classname` -- an optional string that identifies the name of the JDBC driver class to be used for the connection; for common database types, `next.jdbc` knows the default so this should only be needed for "exotic" database types,
|
||||||
* `:user` -- an optional string that identifies the database username to be used when authenticating,
|
* `:user` -- an optional string that identifies the database username to be used when authenticating,
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,14 @@
|
||||||
* `:classname` -- if you need to override the default for the `:dbtype`
|
* `:classname` -- if you need to override the default for the `:dbtype`
|
||||||
(or you want to use a database that next.jdbc does not know about!)
|
(or you want to use a database that next.jdbc does not know about!)
|
||||||
|
|
||||||
|
The following optional keys can be used to control how JDBC URLs are
|
||||||
|
assembled. This may be needed for `:dbtype` values that `next.jdbc`
|
||||||
|
does not recognize:
|
||||||
|
* `:dbname-separator` -- override the `/` or `:` that normally precedes
|
||||||
|
the database name in the JDBC URL
|
||||||
|
* `:host-prefix` -- override the `//` that normally precedes the IP
|
||||||
|
address or hostname in the JDBC URL
|
||||||
|
|
||||||
Any additional options provided will be passed to the JDBC driver's
|
Any additional options provided will be passed to the JDBC driver's
|
||||||
`.getConnection` call as a `java.util.Properties` structure.
|
`.getConnection` call as a `java.util.Properties` structure.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,8 @@
|
||||||
"A map of all known database types (including aliases) to the class name(s)
|
"A map of all known database types (including aliases) to the class name(s)
|
||||||
and port that `next.jdbc` supports out of the box. Just for completeness,
|
and port that `next.jdbc` supports out of the box. Just for completeness,
|
||||||
this also includes the prefixes used in the JDBC string for the `:host`
|
this also includes the prefixes used in the JDBC string for the `:host`
|
||||||
and `:dbname` (which are `//` and `/` respectively for nearly all types).
|
and `:dbname` (which are `//` and either `/` or `:` respectively for
|
||||||
|
nearly all types).
|
||||||
|
|
||||||
For known database types, you can use `:dbtype` (and omit `:classname`).
|
For known database types, you can use `:dbtype` (and omit `:classname`).
|
||||||
|
|
||||||
|
|
@ -81,6 +82,24 @@
|
||||||
|
|
||||||
`{:dbtype \"acme\" :classname \"com.acme.JdbcDriver\" ...}`
|
`{:dbtype \"acme\" :classname \"com.acme.JdbcDriver\" ...}`
|
||||||
|
|
||||||
|
The value of `:dbtype` should be the string that the driver is associated
|
||||||
|
with in the JDBC URL, i.e., the value that comes between the `jdbc:`
|
||||||
|
prefix and the `://<host>...` part. In the above example, the JDBC URL
|
||||||
|
that would be generated would be `jdbc:acme://<host>:<port>/<dbname>`.
|
||||||
|
|
||||||
|
If you want `next.jdbc` to omit the host/port part of the URL, specify
|
||||||
|
`:host :none`, which would produce a URL like: `jdbc:acme:<dbname>`,
|
||||||
|
which allows you to work with local databases (or drivers that do not
|
||||||
|
need host/port information).
|
||||||
|
|
||||||
|
The default prefix for the host name (or IP address) is `//`. You
|
||||||
|
can override this via the `:host-prefix` option.
|
||||||
|
|
||||||
|
The default separator between the host/port and the database name is `/`.
|
||||||
|
The default separator between the subprotocol and the database name,
|
||||||
|
for local databases with no host/port, is `:`. You can override this
|
||||||
|
via the `:dbname-separator` option.
|
||||||
|
|
||||||
JDBC drivers are not provided by `next.jdbc` -- you need to specify the
|
JDBC drivers are not provided by `next.jdbc` -- you need to specify the
|
||||||
driver(s) you need as additional dependencies in your project. For
|
driver(s) you need as additional dependencies in your project. For
|
||||||
example:
|
example:
|
||||||
|
|
@ -127,32 +146,44 @@
|
||||||
|
|
||||||
(defn- spec->url+etc
|
(defn- spec->url+etc
|
||||||
"Given a database spec, return a JDBC URL and a map of any additional options."
|
"Given a database spec, return a JDBC URL and a map of any additional options."
|
||||||
[{:keys [dbtype dbname host port classname] :as db-spec}]
|
[{:keys [dbtype dbname host port classname
|
||||||
|
dbname-separator host-prefix]
|
||||||
|
:as db-spec}]
|
||||||
(let [;; allow aliases for dbtype
|
(let [;; allow aliases for dbtype
|
||||||
subprotocol (aliases dbtype dbtype)
|
subprotocol (aliases dbtype dbtype)
|
||||||
host (or host "127.0.0.1")
|
host (or host "127.0.0.1")
|
||||||
port (or port (ports subprotocol))
|
port (or port (ports subprotocol))
|
||||||
db-sep (dbname-separators dbtype "/")
|
db-sep (or dbname-separator (dbname-separators dbtype "/"))
|
||||||
url (cond (= "h2:mem" dbtype)
|
local-sep (or dbname-separator (dbname-separators dbtype ":"))
|
||||||
(str "jdbc:" subprotocol ":" dbname ";DB_CLOSE_DELAY=-1")
|
url (cond (#{"derby" "hsqldb" "sqlite"} subprotocol)
|
||||||
|
(str "jdbc:" subprotocol local-sep dbname)
|
||||||
|
|
||||||
(#{"h2"} subprotocol)
|
(#{"h2"} subprotocol)
|
||||||
(str "jdbc:" subprotocol ":"
|
(str "jdbc:" subprotocol local-sep
|
||||||
(if (re-find #"^([A-Za-z]:)?[\./\\]" dbname)
|
(if (re-find #"^([A-Za-z]:)?[\./\\]" dbname)
|
||||||
;; DB name starts with relative or absolute path
|
;; DB name starts with relative or absolute path
|
||||||
dbname
|
dbname
|
||||||
;; otherwise make it local
|
;; otherwise make it local
|
||||||
(str "./" dbname)))
|
(str "./" dbname)))
|
||||||
(#{"derby" "hsqldb" "sqlite"} subprotocol)
|
|
||||||
(str "jdbc:" subprotocol ":" dbname)
|
(#{"h2:mem"} subprotocol)
|
||||||
(#{"timesten:direct"} subprotocol)
|
(str "jdbc:" subprotocol local-sep dbname ";DB_CLOSE_DELAY=-1")
|
||||||
(str "jdbc:" subprotocol db-sep dbname)
|
|
||||||
|
(#{"timesten:client" "timesten:direct"} subprotocol)
|
||||||
|
(str "jdbc:" subprotocol local-sep dbname)
|
||||||
|
|
||||||
|
(= :none host)
|
||||||
|
(str "jdbc:" subprotocol local-sep dbname)
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(str "jdbc:" subprotocol ":"
|
(str "jdbc:" subprotocol ":"
|
||||||
(host-prefixes subprotocol "//")
|
(or host-prefix (host-prefixes subprotocol "//"))
|
||||||
host
|
host
|
||||||
(when port (str ":" port))
|
(when port (str ":" port))
|
||||||
db-sep dbname))
|
db-sep dbname))
|
||||||
etc (dissoc db-spec :dbtype :dbname :host :port :classname)]
|
etc (dissoc db-spec
|
||||||
|
:dbtype :dbname :host :port :classname
|
||||||
|
:dbname-separator :host-prefix)]
|
||||||
;; verify the datasource is loadable
|
;; verify the datasource is loadable
|
||||||
(if-let [class-name (or classname (classnames subprotocol))]
|
(if-let [class-name (or classname (classnames subprotocol))]
|
||||||
(swap! driver-cache update class-name
|
(swap! driver-cache update class-name
|
||||||
|
|
|
||||||
|
|
@ -26,15 +26,20 @@
|
||||||
|
|
||||||
(s/def ::dbtype string?)
|
(s/def ::dbtype string?)
|
||||||
(s/def ::dbname string?)
|
(s/def ::dbname string?)
|
||||||
|
(s/def ::dbname-separator string?)
|
||||||
(s/def ::classname string?)
|
(s/def ::classname string?)
|
||||||
(s/def ::user string?)
|
(s/def ::user string?)
|
||||||
(s/def ::password string?)
|
(s/def ::password string?)
|
||||||
(s/def ::host string?)
|
(s/def ::host (s/or :name string?
|
||||||
|
:none #{:none}))
|
||||||
|
(s/def ::host-prefix string?)
|
||||||
(s/def ::port pos-int?)
|
(s/def ::port pos-int?)
|
||||||
(s/def ::db-spec-map (s/keys :req-un [::dbtype ::dbname]
|
(s/def ::db-spec-map (s/keys :req-un [::dbtype ::dbname]
|
||||||
:opt-un [::classname
|
:opt-un [::classname
|
||||||
::user ::password
|
::user ::password
|
||||||
::host ::port]))
|
::host ::port
|
||||||
|
::dbname-separator
|
||||||
|
::host-prefix]))
|
||||||
|
|
||||||
(s/def ::connection #(instance? Connection %))
|
(s/def ::connection #(instance? Connection %))
|
||||||
(s/def ::datasource #(instance? DataSource %))
|
(s/def ::datasource #(instance? DataSource %))
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,29 @@
|
||||||
(is (= (#'c/spec->url+etc {:dbtype "sqlserver" :dbname db-name})
|
(is (= (#'c/spec->url+etc {:dbtype "sqlserver" :dbname db-name})
|
||||||
(#'c/spec->url+etc {:dbtype "sqlserver" :dbname db-name :port 1433})))))
|
(#'c/spec->url+etc {:dbtype "sqlserver" :dbname db-name :port 1433})))))
|
||||||
|
|
||||||
|
(deftest custom-dbtypes
|
||||||
|
(is (= ["jdbc:acme:my-db" {}]
|
||||||
|
(#'c/spec->url+etc {:dbtype "acme" :classname "java.lang.String"
|
||||||
|
:dbname "my-db" :host :none})))
|
||||||
|
(is (= ["jdbc:acme://127.0.0.1/my-db" {}]
|
||||||
|
(#'c/spec->url+etc {:dbtype "acme" :classname "java.lang.String"
|
||||||
|
:dbname "my-db"})))
|
||||||
|
(is (= ["jdbc:acme://12.34.56.70:1234/my-db" {}]
|
||||||
|
(#'c/spec->url+etc {:dbtype "acme" :classname "java.lang.String"
|
||||||
|
:dbname "my-db" :host "12.34.56.70" :port 1234})))
|
||||||
|
(is (= ["jdbc:acme:dsn=my-db" {}]
|
||||||
|
(#'c/spec->url+etc {:dbtype "acme" :classname "java.lang.String"
|
||||||
|
:dbname "my-db" :host :none
|
||||||
|
:dbname-separator ":dsn="})))
|
||||||
|
(is (= ["jdbc:acme:(*)127.0.0.1/my-db" {}]
|
||||||
|
(#'c/spec->url+etc {:dbtype "acme" :classname "java.lang.String"
|
||||||
|
:dbname "my-db"
|
||||||
|
:host-prefix "(*)"})))
|
||||||
|
(is (= ["jdbc:acme:(*)12.34.56.70:1234/my-db" {}]
|
||||||
|
(#'c/spec->url+etc {:dbtype "acme" :classname "java.lang.String"
|
||||||
|
:dbname "my-db" :host "12.34.56.70" :port 1234
|
||||||
|
:host-prefix "(*)"}))))
|
||||||
|
|
||||||
;; these are the 'local' databases that we can always test against
|
;; these are the 'local' databases that we can always test against
|
||||||
(def test-db-type ["derby" "h2" "h2:mem" "hsqldb" "sqlite"])
|
(def test-db-type ["derby" "h2" "h2:mem" "hsqldb" "sqlite"])
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue