Browse files

Replace c3p0 with hikari

  • Loading branch information...
Sean Walker
Sean Walker committed Jan 3, 2019
1 parent 2a5ece0 commit 2857f1a2e5d2eff6857eb87e4e8564bd11d2384b
Showing with 77 additions and 36 deletions.
  1. +2 −1 deps.edn
  2. +64 −35 src/coast/db/connection.clj
  3. +11 −0 src/coast/utils.clj
@@ -1,7 +1,8 @@
{:paths ["src" "resources"]

:deps {asset-minifier {:mvn/version "0.2.5"}
com.mchange/c3p0 {:mvn/version ""}
com.zaxxer/HikariCP {:mvn/version "2.7.8"}
org.slf4j/slf4j-nop {:mvn/version "1.7.25"}
hiccup {:mvn/version "2.0.0-alpha1"}
http-kit {:mvn/version "2.3.0"}
jkkramer/verily {:mvn/version "0.6.0"}
@@ -1,13 +1,8 @@
(ns coast.db.connection
(:require [coast.env :refer [env]]
[clojure.string :as string])
(:import (com.mchange.v2.c3p0 ComboPooledDataSource)))
(:import (com.zaxxer.hikari HikariConfig HikariDataSource)))

; turn off logging in c3p0
(doto (java.util.Properties. (System/getProperties))
(.put "com.mchange.v2.log.MLog" "com.mchange.v2.log.FallbackMLog")
(.put "com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL" "OFF")))

(defn db-url []
(let [url (or (env :database-url)
@@ -16,6 +11,7 @@
(throw (Exception. "Your database connection string is blank. Set the DATABASE_URL or DB_SPEC_OR_URL environment variable"))

(defn admin-db-url []
(let [url (or (env :admin-db-spec-or-url)
(env :admin-database-url)
@@ -24,34 +20,67 @@
(throw (Exception. "Your admin database connection string is blank. Set the ADMIN_DB_SPEC_OR_URL environment variable"))

(defn user-info [db-uri]
(when (string? (.getUserInfo db-uri))
(let [[user password] (string/split (.getUserInfo db-uri) #":")]
{:user user :password password})))

(defn db-spec []
(let [uri ( (db-url))
user (user-info uri)]
{:classname "org.postgresql.Driver"
:subprotocol "postgresql"
:user (:user user)
:password (:password user)
:subname (if (= -1 (.getPort uri))
(format "//%s%s" (.getHost uri) (.getPath uri))
(format "//%s:%s%s" (.getHost uri) (.getPort uri) (.getPath uri)))}))

(defn pool [db-spec]
(let [cpds (doto (ComboPooledDataSource.)
(.setDriverClass (:classname db-spec))
(.setJdbcUrl (str "jdbc:" (:subprotocol db-spec) ":" (:subname db-spec)))
(.setUser (:user db-spec))
(.setPassword (:password db-spec))
;; expire excess connections after 30 minutes of inactivity:
(.setMaxIdleTimeExcessConnections (* 30 60))
;; expire connections after 3 hours of inactivity:
(.setMaxIdleTime (* 3 60 60)))]
{:datasource cpds}))

(def pooled-db (delay (pool (db-spec))))

(defn sqlite? [arg]
(string? arg) (> (.indexOf arg "sqlite") -1)
(map? arg) (sqlite? (.getJdbcUrl (:datasource arg)))
:else false))

(defn pg? [arg]
(string? arg) (> (.indexOf arg "postgres") -1)
(map? arg) (pg? (.getJdbcUrl (:datasource arg)))
:else false))

(defn driver [s]
"Determines which driver class to pass into the hikari cp config"
(when (string? s)
(sqlite? s) :sqlite
(pg? s) :pg
:else nil)))

(def driver-class-names {:sqlite "org.sqlite.JDBC"
:pg "org.postgresql.Driver"})

(def opts {:auto-commit true
:read-only false
:connection-timeout 30000
:validation-timeout 5000
:idle-timeout 600000
:max-lifetime 1800000
:minimum-idle 10
:maximum-pool-size 10
:register-mbeans false})

(defn pool
"Shamelessly stolen from hikari-cp and makes a new hikaricp data source"
[s m]
(let [m (merge opts m)
driver (driver s)
connection-init-sql (when (= :sqlite driver)
"PRAGMA foreign_keys=ON")
_ (when (nil? driver)
(throw (Exception. "Unsupported connection string, only sqlite and postgres are supported currently")))
c (doto (HikariConfig.)
(.setDriverClassName (get driver-class-names driver))
(.setJdbcUrl s)
(.setAutoCommit (:auto-commit m))
(.setReadOnly (:read-only m))
(.setConnectionTimeout (:connection-timeout m))
(.setValidationTimeout (:validation-timeout m))
(.setIdleTimeout (:idle-timeout m))
(.setMaxLifetime (:max-lifetime m))
(.setMinimumIdle (:minimum-idle m))
(.setMaximumPoolSize (:maximum-pool-size m))
(.setConnectionInitSql connection-init-sql))]
{:datasource (HikariDataSource. c)}))

(def pooled-db (delay (pool (db-url) opts)))

(defn connection [] @pooled-db)
@@ -61,6 +61,9 @@
(def kebab (partial convert-case #"_" "-"))
(def snake (partial convert-case #"-" "_"))

(def kebab-case (partial convert-case #"_" "-"))
(def snake-case (partial convert-case #"-" "_"))

(defn long-str [& s]
(let [s (filter some? s)]
(if (= 1 (count s))
@@ -97,3 +100,11 @@
(defn resolve-safely [sym]
(when (symbol? sym)
(resolve sym)))

(defn sqlize [val]
(qualified-ident? val) (str (-> val namespace snake-case) "." (-> val name snake-case))
(ident? val) (-> val name snake-case)
(string? val) (snake-case val)
(nil? val) val
:else (throw (Exception. (str val " is not an ident or a string. Example: :customer, :public/customer or \"customer\"")))))

0 comments on commit 2857f1a

Please sign in to comment.