Provide built-in support for Stuart Sierra's Component library
Needs documenting!
This commit is contained in:
parent
905f7c3e12
commit
66fdba4be9
1 changed files with 76 additions and 0 deletions
|
|
@ -230,6 +230,82 @@
|
||||||
(let [[url etc] (spec->url+etc db-spec)]
|
(let [[url etc] (spec->url+etc db-spec)]
|
||||||
(j/to-java clazz (assoc etc :jdbcUrl url)))))
|
(j/to-java clazz (assoc etc :jdbcUrl url)))))
|
||||||
|
|
||||||
|
(defn- attempt-close
|
||||||
|
"Given an arbitrary object that almost certainly supports a `.close`
|
||||||
|
method that takes no arguments and returns `void`, try to find it
|
||||||
|
and call it."
|
||||||
|
[obj]
|
||||||
|
(let [^Class clazz (class obj)
|
||||||
|
^java.lang.reflect.Method close
|
||||||
|
(->> (.getMethods clazz)
|
||||||
|
(filter (fn [^java.lang.reflect.Method m]
|
||||||
|
(and (= "close" (.getName m))
|
||||||
|
(empty? (.getParameterTypes m))
|
||||||
|
(= "void" (.getName (.getReturnType m))))))
|
||||||
|
(first))]
|
||||||
|
(when close
|
||||||
|
(.invoke close obj (object-array [])))))
|
||||||
|
|
||||||
|
(defn component
|
||||||
|
"Takes the same arguments as `->pool` but returns an entity compatible
|
||||||
|
with Stuart Sierra's Component: when `com.stuartsierra.component/start`
|
||||||
|
is called on it, it builds a connection pooled datasource, and returns
|
||||||
|
an entity that can either be invoked as a function with no arguments
|
||||||
|
to return that datasource, or can have `com.stuartsierra.component/stop`
|
||||||
|
called on it to shutdown the datasource (and return a new startable
|
||||||
|
entity).
|
||||||
|
|
||||||
|
By default, the datasource is shutdown by calling `.close` on it.
|
||||||
|
If the datasource class implements `java.io.Closeable` then a direct,
|
||||||
|
type-hinted call to `.close` will be used, with no reflection,
|
||||||
|
otherwise Java reflection will be used to find the first `.close`
|
||||||
|
method in the datasource class that takes no arguments and returns `void`.
|
||||||
|
|
||||||
|
If neither of those behaviors is appropriate, you may supply a third
|
||||||
|
argument to this function -- `close-fn` -- which performs whatever
|
||||||
|
action is appropriate to your chosen datasource class."
|
||||||
|
([clazz db-spec]
|
||||||
|
(component clazz db-spec #(if (isa? clazz java.io.Closeable)
|
||||||
|
(.close ^java.io.Closeable %)
|
||||||
|
(attempt-close %))))
|
||||||
|
([clazz db-spec close-fn]
|
||||||
|
(with-meta {}
|
||||||
|
{'com.stuartsierra.component/start
|
||||||
|
(fn [_]
|
||||||
|
(let [pool (->pool clazz db-spec)]
|
||||||
|
(with-meta (fn ^DataSource [] pool)
|
||||||
|
{'com.stuartsierra.component/stop
|
||||||
|
(fn [_]
|
||||||
|
(close-fn pool)
|
||||||
|
(component clazz db-spec close-fn))})))})))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(require '[com.stuartsierra.component :as component])
|
||||||
|
(import '(com.mchange.v2.c3p0 ComboPooledDataSource PooledDataSource)
|
||||||
|
'(com.zaxxer.hikari HikariDataSource))
|
||||||
|
(isa? PooledDataSource java.io.Closeable) ;=> false
|
||||||
|
(isa? HikariDataSource java.io.Closeable) ;=> true
|
||||||
|
;; use c3p0 with default reflection-based closing function:
|
||||||
|
(def dbc (component ComboPooledDataSource
|
||||||
|
{:dbtype "mysql" :dbname "clojure_test"
|
||||||
|
:user "clojure_test" :password "clojure_test"}))
|
||||||
|
;; use c3p0 with a type-hinted closing function:
|
||||||
|
(def dbc (component ComboPooledDataSource
|
||||||
|
{:dbtype "mysql" :dbname "clojure_test"
|
||||||
|
:user "clojure_test" :password "clojure_test"}
|
||||||
|
#(.close ^PooledDataSource %)))
|
||||||
|
;; use HikariCP with default Closeable .close function:
|
||||||
|
(def dbc (component HikariDataSource
|
||||||
|
{:dbtype "mysql" :dbname "clojure_test"
|
||||||
|
;; HikariCP requires :username, not :user
|
||||||
|
:username "clojure_test" :password "clojure_test"}))
|
||||||
|
;; start the chosen datasource component:
|
||||||
|
(def ds (component/start dbc))
|
||||||
|
;; invoke datasource component to get the underlying javax.sql.DataSource:
|
||||||
|
(next.jdbc.sql/get-by-id (ds) :fruit 1)
|
||||||
|
;; stop the component and close the pooled datasource:
|
||||||
|
(component/stop ds))
|
||||||
|
|
||||||
(defn- string->url+etc
|
(defn- string->url+etc
|
||||||
"Given a JDBC URL, return it with an empty set of options with no parsing."
|
"Given a JDBC URL, return it with an empty set of options with no parsing."
|
||||||
[s]
|
[s]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue