Fix #47 by refactoring how db-specs are built
This commit is contained in:
parent
e0e209aa1c
commit
816fc7ce4b
2 changed files with 56 additions and 76 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 #47 by refactoring database specs to be a single hash map instead of pouring multiple maps into one.
|
||||||
* Fix #46 by allowing `:host` to be `:none` which tells `next.jdbc` to 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 added `:dbname-separator` and `:host-prefix` to the "db-spec" to allow fine-grained control over how the JDBC URL is assembled.
|
* Fix #46 by allowing `:host` to be `:none` which tells `next.jdbc` to 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 added `: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 `[]`.
|
||||||
|
|
|
||||||
|
|
@ -9,65 +9,7 @@
|
||||||
|
|
||||||
(set! *warn-on-reflection* true)
|
(set! *warn-on-reflection* true)
|
||||||
|
|
||||||
(def ^:private classnames
|
(def ^:private dbtypes
|
||||||
"Map of subprotocols to classnames. `:dbtype` specifies one of these keys.
|
|
||||||
|
|
||||||
The subprotocols map below provides aliases for `:dbtype`.
|
|
||||||
|
|
||||||
Most databases have just a single class name for their driver but we
|
|
||||||
support a sequence of class names to try in order to allow for drivers
|
|
||||||
that change their names over time (e.g., MySQL)."
|
|
||||||
{"derby" "org.apache.derby.jdbc.EmbeddedDriver"
|
|
||||||
"h2" "org.h2.Driver"
|
|
||||||
"h2:mem" "org.h2.Driver"
|
|
||||||
"hsqldb" "org.hsqldb.jdbcDriver"
|
|
||||||
"jtds:sqlserver" "net.sourceforge.jtds.jdbc.Driver"
|
|
||||||
"mysql" ["com.mysql.cj.jdbc.Driver"
|
|
||||||
"com.mysql.jdbc.Driver"]
|
|
||||||
"oracle:oci" "oracle.jdbc.OracleDriver"
|
|
||||||
"oracle:thin" "oracle.jdbc.OracleDriver"
|
|
||||||
"postgresql" "org.postgresql.Driver"
|
|
||||||
"pgsql" "com.impossibl.postgres.jdbc.PGDriver"
|
|
||||||
"redshift" "com.amazon.redshift.jdbc.Driver"
|
|
||||||
"sqlite" "org.sqlite.JDBC"
|
|
||||||
"sqlserver" "com.microsoft.sqlserver.jdbc.SQLServerDriver"
|
|
||||||
"timesten:client" "com.timesten.jdbc.TimesTenClientDriver"
|
|
||||||
"timesten:direct" "com.timesten.jdbc.TimesTenDriver"})
|
|
||||||
|
|
||||||
(def ^:private aliases
|
|
||||||
"Map of schemes to subprotocols. Used to provide aliases for `:dbtype`."
|
|
||||||
{"hsql" "hsqldb"
|
|
||||||
"jtds" "jtds:sqlserver"
|
|
||||||
"mssql" "sqlserver"
|
|
||||||
"oracle" "oracle:thin"
|
|
||||||
"oracle:sid" "oracle:thin"
|
|
||||||
"postgres" "postgresql"})
|
|
||||||
|
|
||||||
(def ^:private host-prefixes
|
|
||||||
"Map of subprotocols to non-standard host-prefixes.
|
|
||||||
Anything not listed is assumed to use `//`."
|
|
||||||
{"oracle:oci" "@"
|
|
||||||
"oracle:thin" "@"})
|
|
||||||
|
|
||||||
(def ^:private ports
|
|
||||||
"Map of subprotocols to ports."
|
|
||||||
{"jtds:sqlserver" 1433
|
|
||||||
"mysql" 3306
|
|
||||||
"oracle:oci" 1521
|
|
||||||
"oracle:sid" 1521
|
|
||||||
"oracle:thin" 1521
|
|
||||||
"postgresql" 5432
|
|
||||||
"sqlserver" 1433})
|
|
||||||
|
|
||||||
(def ^:private dbname-separators
|
|
||||||
"Map of schemes to separators. The default is `/` but a couple are different."
|
|
||||||
{"mssql" ";DATABASENAME="
|
|
||||||
"sqlserver" ";DATABASENAME="
|
|
||||||
"oracle:sid" ":"
|
|
||||||
"timesten:client" ":dsn="
|
|
||||||
"timesten:direct" ":dsn="})
|
|
||||||
|
|
||||||
(def dbtypes
|
|
||||||
"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`
|
||||||
|
|
@ -113,17 +55,54 @@
|
||||||
named class in order, until one succeeds. This allows for a given `:dbtype`
|
named class in order, until one succeeds. This allows for a given `:dbtype`
|
||||||
to be used with different versions of a JDBC driver, if the class name
|
to be used with different versions of a JDBC driver, if the class name
|
||||||
has changed over time (such as with MySQL)."
|
has changed over time (such as with MySQL)."
|
||||||
(let [dbs (merge (zipmap (keys classnames) (keys classnames)) aliases)]
|
{"derby" {:classname "org.apache.derby.jdbc.EmbeddedDriver"}
|
||||||
(reduce-kv (fn [m k v]
|
"h2" {:classname "org.h2.Driver"}
|
||||||
(assoc m
|
"h2:mem" {:classname "org.h2.Driver"}
|
||||||
k
|
"hsql" {:classname "org.hsqldb.jdbcDriver"
|
||||||
(cond-> {:classname (classnames v)
|
:alias-for "hsqldb"}
|
||||||
:host-prefix (host-prefixes v "//")
|
"hsqldb" {:classname "org.hsqldb.jdbcDriver"}
|
||||||
:dbname-separator (dbname-separators v "/")}
|
"jtds" {:classname "net.sourceforge.jtds.jdbc.Driver"
|
||||||
(ports v)
|
:port 1433
|
||||||
(assoc :port (ports v)))))
|
:alias-for "jtds:sqlserver"}
|
||||||
{}
|
"jtds:sqlserver" {:classname "net.sourceforge.jtds.jdbc.Driver"
|
||||||
dbs)))
|
:port 1433}
|
||||||
|
"mssql" {:classname "com.microsoft.sqlserver.jdbc.SQLServerDriver"
|
||||||
|
:port 1433
|
||||||
|
:alias-for "sqlserver"
|
||||||
|
:dbname-separator ";DATABASENAME="}
|
||||||
|
"mysql" {:classname ["com.mysql.cj.jdbc.Driver"
|
||||||
|
"com.mysql.jdbc.Driver"]
|
||||||
|
:port 3306}
|
||||||
|
"oracle" {:classname "oracle.jdbc.OracleDriver"
|
||||||
|
:port 1521
|
||||||
|
:alias-for "oracle:thin"
|
||||||
|
:host-prefix "@"}
|
||||||
|
"oracle:oci" {:classname "oracle.jdbc.OracleDriver"
|
||||||
|
:port 1521
|
||||||
|
:host-prefix "@"}
|
||||||
|
"oracle:sid" {:classname "oracle.jdbc.OracleDriver"
|
||||||
|
:port 1521
|
||||||
|
:alias-for "oracle:thin"
|
||||||
|
:dbname-separator ":"
|
||||||
|
:host-prefix "@"}
|
||||||
|
"oracle:thin" {:classname "oracle.jdbc.OracleDriver"
|
||||||
|
:port 1521
|
||||||
|
:host-prefix "@"}
|
||||||
|
"postgres" {:classname "org.postgresql.Driver"
|
||||||
|
:port 5432
|
||||||
|
:alias-for "postgresql"}
|
||||||
|
"postgresql" {:classname "org.postgresql.Driver"
|
||||||
|
:port 5432}
|
||||||
|
"pgsql" {:classname "com.impossibl.postgres.jdbc.PGDriver"}
|
||||||
|
"redshift" {:classname "com.amazon.redshift.jdbc.Driver"}
|
||||||
|
"sqlite" {:classname "org.sqlite.JDBC"}
|
||||||
|
"sqlserver" {:classname "com.microsoft.sqlserver.jdbc.SQLServerDriver"
|
||||||
|
:port 1433
|
||||||
|
:dbname-separator ";DATABASENAME="}
|
||||||
|
"timesten:client" {:classname "com.timesten.jdbc.TimesTenClientDriver"
|
||||||
|
:dbname-separator ":dsn="}
|
||||||
|
"timesten:direct" {:classname "com.timesten.jdbc.TimesTenDriver"
|
||||||
|
:dbname-separator ":dsn="}})
|
||||||
|
|
||||||
(defn- ^Properties as-properties
|
(defn- ^Properties as-properties
|
||||||
"Convert any seq of pairs to a `java.util.Properties` instance."
|
"Convert any seq of pairs to a `java.util.Properties` instance."
|
||||||
|
|
@ -150,11 +129,11 @@
|
||||||
dbname-separator host-prefix]
|
dbname-separator host-prefix]
|
||||||
:as db-spec}]
|
:as db-spec}]
|
||||||
(let [;; allow aliases for dbtype
|
(let [;; allow aliases for dbtype
|
||||||
subprotocol (aliases dbtype dbtype)
|
subprotocol (-> dbtype dbtypes :alias-for (or dbtype))
|
||||||
host (or host "127.0.0.1")
|
host (or host "127.0.0.1")
|
||||||
port (or port (ports subprotocol))
|
port (or port (-> dbtype dbtypes :port))
|
||||||
db-sep (or dbname-separator (dbname-separators dbtype "/"))
|
db-sep (or dbname-separator (-> dbtype dbtypes :dbname-separator (or "/")))
|
||||||
local-sep (or dbname-separator (dbname-separators dbtype ":"))
|
local-sep (or dbname-separator (-> dbtype dbtypes :dbname-separator (or ":")))
|
||||||
url (cond (#{"derby" "hsqldb" "sqlite"} subprotocol)
|
url (cond (#{"derby" "hsqldb" "sqlite"} subprotocol)
|
||||||
(str "jdbc:" subprotocol local-sep dbname)
|
(str "jdbc:" subprotocol local-sep dbname)
|
||||||
|
|
||||||
|
|
@ -177,7 +156,7 @@
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(str "jdbc:" subprotocol ":"
|
(str "jdbc:" subprotocol ":"
|
||||||
(or host-prefix (host-prefixes subprotocol "//"))
|
(or host-prefix (-> dbtype dbtypes :host-prefix (or "//")))
|
||||||
host
|
host
|
||||||
(when port (str ":" port))
|
(when port (str ":" port))
|
||||||
db-sep dbname))
|
db-sep dbname))
|
||||||
|
|
@ -185,7 +164,7 @@
|
||||||
:dbtype :dbname :host :port :classname
|
:dbtype :dbname :host :port :classname
|
||||||
:dbname-separator :host-prefix)]
|
: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 (-> dbtype dbtypes :classname))]
|
||||||
(swap! driver-cache update class-name
|
(swap! driver-cache update class-name
|
||||||
#(if % %
|
#(if % %
|
||||||
(do
|
(do
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue