Back

->pool (clj)

(source)

function

(->pool clazz db-spec)
Given a (connection pooled datasource) class and a database spec, return a connection pool object built from that class and the database spec. Assumes the `clazz` has a `.setJdbcUrl` method (which HikariCP and c3p0 do). If you already have a JDBC URL and want to use this method, pass `:jdbcUrl` in the database spec (instead of `:dbtype`, `:dbname`, etc). Properties for the connection pool object can be passed as mixed case keywords that correspond to setter methods (just as `:jdbcUrl` maps to `.setJdbcUrl`). `clojure.java.data/to-java` is used to construct the object and call the setters. If you need to pass in connection URL parameters, it can be easier to use `next.jdbc.connection/jdbc-url` to construct URL, e.g., (->pool HikariDataSource {:jdbcUrl (jdbc-url {:dbtype .. :dbname .. :useSSL false}) :username .. :password ..}) Here we pass `:useSSL false` to `jdbc-url` so that it ends up in the connection string, but pass `:username` and `:password` for the pool itself. Note that the result is not type-hinted (because there's no common base class or interface that can be assumed). In particular, connection pooled datasource objects may need to be closed but they don't necessarily implement `java.io.Closeable` (HikariCP does, c3p0 does not).

Examples

next-jdbc
(ns next.jdbc-test
  "Basic tests for the primary API of `next.jdbc`."
  (:require [clojure.core.reducers :as r]
            [clojure.string :as str]
            [clojure.test :refer [deftest is testing use-fixtures]]
            [next.jdbc :as jdbc]
            [next.jdbc.connection :as c]
            [next.jdbc.test-fixtures
             :refer [with-test-db db ds column
                     default-options stored-proc?
                     derby? hsqldb? jtds? mssql? mysql? postgres? sqlite?]]
            [next.jdbc.prepare :as prep]
            [next.jdbc.result-set :as rs]
            [next.jdbc.specs :as specs]
            [next.jdbc.types :as types])
  (:import (com.zaxxer.hikari HikariDataSource)
           (com.mchange.v2.c3p0 ComboPooledDataSource PooledDataSource)
           (java.sql ResultSet ResultSetMetaData)))

(deftest issue-146
  ;; since we use an embedded PostgreSQL data source, we skip this:
  (when-not (or (postgres?)
                ;; and now we skip MS SQL because we can't use the db-spec
                ;; we'd need to build the jdbcUrl with encryption turned off:
                (and (mssql?) (not (jtds?))))
    (testing "Hikari and SavePoints"
      (with-open [^HikariDataSource ds (c/->pool HikariDataSource
                                        (let [db (db)]
                                          (cond-> db
                                            ;; jTDS does not support isValid():
                                            (jtds?)
                                            (assoc :connectionTestQuery "SELECT 1")
                                            ;; HikariCP needs username, not user:
                                            (contains? db :user)
                                            (assoc :username (:user db)))))]
        (testing "with-transaction with unnamed save point"
          (is (= [{:next.jdbc/update-count 1}]
                (jdbc/with-transaction [t ds]
                  (let [save-point (.setSavepoint t)
                        result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                    (.rollback t save-point)
                    result))))
          (is (= 4 (count (jdbc/execute! ds ["select * from fruit"]))))
          (with-open [con (jdbc/get-connection ds)]
            (let [ac (.getAutoCommit con)]
              (is (= [{:next.jdbc/update-count 1}]
                    (jdbc/with-transaction [t con]
                      (let [save-point (.setSavepoint t)
                            result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                        (.rollback t save-point)
                        result))))
              (is (= 4 (count (jdbc/execute! con ["select * from fruit"]))))
              (is (= ac (.getAutoCommit con))))))
        (testing "with-transaction with named save point"
          (is (= [{:next.jdbc/update-count 1}]
                (jdbc/with-transaction [t ds]
                  (let [save-point (.setSavepoint t (name (gensym)))
                        result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                    (.rollback t save-point)
                    result))))
          (is (= 4 (count (jdbc/execute! ds ["select * from fruit"]))))
          (with-open [con (jdbc/get-connection ds)]
            (let [ac (.getAutoCommit con)]
              (is (= [{:next.jdbc/update-count 1}]
                    (jdbc/with-transaction [t con]
                      (let [save-point (.setSavepoint t (name (gensym)))
                            result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                        (.rollback t save-point)
                        result))))
              (is (= 4 (count (jdbc/execute! con ["select * from fruit"]))))
              (is (= ac (.getAutoCommit con))))))))
    (testing "c3p0 and SavePoints"
      (with-open [^PooledDataSource ds (c/->pool ComboPooledDataSource (db))]
        (testing "with-transaction with unnamed save point"
          (is (= [{:next.jdbc/update-count 1}]
                (jdbc/with-transaction [t ds]
                  (let [save-point (.setSavepoint t)
                        result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                    (.rollback t save-point)
                    result))))
          (is (= 4 (count (jdbc/execute! ds ["select * from fruit"]))))
          (with-open [con (jdbc/get-connection ds)]
            (let [ac (.getAutoCommit con)]
              (is (= [{:next.jdbc/update-count 1}]
                    (jdbc/with-transaction [t con]
                      (let [save-point (.setSavepoint t)
                            result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                        (.rollback t save-point)
                        result))))
              (is (= 4 (count (jdbc/execute! con ["select * from fruit"]))))
              (is (= ac (.getAutoCommit con))))))
        (testing "with-transaction with named save point"
          (is (= [{:next.jdbc/update-count 1}]
                (jdbc/with-transaction [t ds]
                  (let [save-point (.setSavepoint t (name (gensym)))
                        result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                    (.rollback t save-point)
                    result))))
          (is (= 4 (count (jdbc/execute! ds ["select * from fruit"]))))
          (with-open [con (jdbc/get-connection ds)]
            (let [ac (.getAutoCommit con)]
              (is (= [{:next.jdbc/update-count 1}]
                    (jdbc/with-transaction [t con]
                      (let [save-point (.setSavepoint t (name (gensym)))
                            result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                        (.rollback t save-point)
                        result))))
              (is (= 4 (count (jdbc/execute! con ["select * from fruit"]))))
              (is (= ac (.getAutoCommit con))))))))))
next-jdbc
  At some point, the datasource/connection tests should probably be extended
  to accept EDN specs from an external source (environment variables?)."
  (:require [clojure.string :as str]
            [clojure.test :refer [deftest is testing]]
            [next.jdbc.connection :as c]
            [next.jdbc.protocols :as p])
  (:import (com.zaxxer.hikari HikariDataSource)
           (com.mchange.v2.c3p0 ComboPooledDataSource PooledDataSource)))

(deftest test-get-connection
  (doseq [db test-dbs]
    (println 'test-get-connection (:dbtype db))
    (testing "datasource via Associative"
      (let [ds (p/get-datasource db)]
        (is (instance? javax.sql.DataSource ds))
        (is (str/index-of (pr-str ds) (str "jdbc:" (:dbtype db))))
        ;; checks get-datasource on a DataSource is identity
        (is (identical? ds (p/get-datasource ds)))
        (with-open [con (p/get-connection ds {})]
          (is (instance? java.sql.Connection con)))))
    (testing "datasource via String"
      (let [[url _] (#'c/spec->url+etc db)
            ds (p/get-datasource url)]
        (is (instance? javax.sql.DataSource ds))
        (is (str/index-of (pr-str ds) url))
        (.setLoginTimeout ds 0)
        (is (= 0 (.getLoginTimeout ds)))
        (with-open [con (p/get-connection ds {})]
          (is (instance? java.sql.Connection con)))))
    (testing "datasource via jdbcUrl"
      (let [[url etc] (#'c/spec->url+etc db)
            ds (p/get-datasource (assoc etc :jdbcUrl url))]
        (if (= "derby" (:dbtype db))
          (is (= {:create true} etc))
          (is (= {} etc)))
        (is (instance? javax.sql.DataSource ds))
        (is (str/index-of (pr-str ds) (str "jdbc:" (:dbtype db))))
        ;; checks get-datasource on a DataSource is identity
        (is (identical? ds (p/get-datasource ds)))
        (.setLoginTimeout ds 1)
        (is (= 1 (.getLoginTimeout ds)))
        (with-open [con (p/get-connection ds {})]
          (is (instance? java.sql.Connection con)))))
    (testing "datasource via HikariCP"
      ;; the type hint is only needed because we want to call .close
      (with-open [^HikariDataSource ds (c/->pool HikariDataSource db)]
        (is (instance? javax.sql.DataSource ds))
        ;; checks get-datasource on a DataSource is identity
        (is (identical? ds (p/get-datasource ds)))
        (with-open [con (p/get-connection ds {})]
          (is (instance? java.sql.Connection con)))))
    (testing "datasource via c3p0"
      ;; the type hint is only needed because we want to call .close
      (with-open [^PooledDataSource ds (c/->pool ComboPooledDataSource db)]
        (is (instance? javax.sql.DataSource ds))
        ;; checks get-datasource on a DataSource is identity
        (is (identical? ds (p/get-datasource ds)))
        (with-open [con (p/get-connection ds {})]
          (is (instance? java.sql.Connection con)))))
    (testing "connection via map (Object)"
      (with-open [con (p/get-connection db {})]
        (is (instance? java.sql.Connection con))))))
seancorfield/next-jdbc
  At some point, the datasource/connection tests should probably be extended
  to accept EDN specs from an external source (environment variables?)."
  (:require [clojure.string :as str]
            [clojure.test :refer [deftest is testing]]
            [next.jdbc.connection :as c]
            [next.jdbc.protocols :as p])
  (:import (com.zaxxer.hikari HikariDataSource)
           (com.mchange.v2.c3p0 ComboPooledDataSource PooledDataSource)))

(deftest test-get-connection
  (doseq [db test-dbs]
    (println 'test-get-connection (:dbtype db))
    (testing "datasource via Associative"
      (let [ds (p/get-datasource db)]
        (is (instance? javax.sql.DataSource ds))
        (is (str/index-of (pr-str ds) (str "jdbc:" (:dbtype db))))
        ;; checks get-datasource on a DataSource is identity
        (is (identical? ds (p/get-datasource ds)))
        (with-open [con (p/get-connection ds {})]
          (is (instance? java.sql.Connection con)))))
    (testing "datasource via String"
      (let [[url _] (#'c/spec->url+etc db)
            ds (p/get-datasource url)]
        (is (instance? javax.sql.DataSource ds))
        (is (str/index-of (pr-str ds) url))
        (.setLoginTimeout ds 0)
        (is (= 0 (.getLoginTimeout ds)))
        (with-open [con (p/get-connection ds {})]
          (is (instance? java.sql.Connection con)))))
    (testing "datasource via jdbcUrl"
      (let [[url etc] (#'c/spec->url+etc db)
            ds (p/get-datasource (assoc etc :jdbcUrl url))]
        (if (= "derby" (:dbtype db))
          (is (= {:create true} etc))
          (is (= {} etc)))
        (is (instance? javax.sql.DataSource ds))
        (is (str/index-of (pr-str ds) (str "jdbc:" (:dbtype db))))
        ;; checks get-datasource on a DataSource is identity
        (is (identical? ds (p/get-datasource ds)))
        (.setLoginTimeout ds 1)
        (is (= 1 (.getLoginTimeout ds)))
        (with-open [con (p/get-connection ds {})]
          (is (instance? java.sql.Connection con)))))
    (testing "datasource via HikariCP"
      ;; the type hint is only needed because we want to call .close
      (with-open [^HikariDataSource ds (c/->pool HikariDataSource db)]
        (is (instance? javax.sql.DataSource ds))
        ;; checks get-datasource on a DataSource is identity
        (is (identical? ds (p/get-datasource ds)))
        (with-open [con (p/get-connection ds {})]
          (is (instance? java.sql.Connection con)))))
    (testing "datasource via c3p0"
      ;; the type hint is only needed because we want to call .close
      (with-open [^PooledDataSource ds (c/->pool ComboPooledDataSource db)]
        (is (instance? javax.sql.DataSource ds))
        ;; checks get-datasource on a DataSource is identity
        (is (identical? ds (p/get-datasource ds)))
        (with-open [con (p/get-connection ds {})]
          (is (instance? java.sql.Connection con)))))
    (testing "connection via map (Object)"
      (with-open [con (p/get-connection db {})]
        (is (instance? java.sql.Connection con))))))
seancorfield/next-jdbc
(ns next.jdbc-test
  "Basic tests for the primary API of `next.jdbc`."
  (:require [clojure.core.reducers :as r]
            [clojure.string :as str]
            [clojure.test :refer [deftest is testing use-fixtures]]
            [next.jdbc :as jdbc]
            [next.jdbc.connection :as c]
            [next.jdbc.test-fixtures
             :refer [with-test-db db ds column
                     default-options stored-proc?
                     derby? hsqldb? jtds? mssql? mysql? postgres? sqlite?]]
            [next.jdbc.prepare :as prep]
            [next.jdbc.result-set :as rs]
            [next.jdbc.specs :as specs]
            [next.jdbc.types :as types])
  (:import (com.zaxxer.hikari HikariDataSource)
           (com.mchange.v2.c3p0 ComboPooledDataSource PooledDataSource)
           (java.sql ResultSet ResultSetMetaData)))

(deftest issue-146
  ;; since we use an embedded PostgreSQL data source, we skip this:
  (when-not (or (postgres?)
                ;; and now we skip MS SQL because we can't use the db-spec
                ;; we'd need to build the jdbcUrl with encryption turned off:
                (and (mssql?) (not (jtds?))))
    (testing "Hikari and SavePoints"
      (with-open [^HikariDataSource ds (c/->pool HikariDataSource
                                        (let [db (db)]
                                          (cond-> db
                                            ;; jTDS does not support isValid():
                                            (jtds?)
                                            (assoc :connectionTestQuery "SELECT 1")
                                            ;; HikariCP needs username, not user:
                                            (contains? db :user)
                                            (assoc :username (:user db)))))]
        (testing "with-transaction with unnamed save point"
          (is (= [{:next.jdbc/update-count 1}]
                (jdbc/with-transaction [t ds]
                  (let [save-point (.setSavepoint t)
                        result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                    (.rollback t save-point)
                    result))))
          (is (= 4 (count (jdbc/execute! ds ["select * from fruit"]))))
          (with-open [con (jdbc/get-connection ds)]
            (let [ac (.getAutoCommit con)]
              (is (= [{:next.jdbc/update-count 1}]
                    (jdbc/with-transaction [t con]
                      (let [save-point (.setSavepoint t)
                            result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                        (.rollback t save-point)
                        result))))
              (is (= 4 (count (jdbc/execute! con ["select * from fruit"]))))
              (is (= ac (.getAutoCommit con))))))
        (testing "with-transaction with named save point"
          (is (= [{:next.jdbc/update-count 1}]
                (jdbc/with-transaction [t ds]
                  (let [save-point (.setSavepoint t (name (gensym)))
                        result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                    (.rollback t save-point)
                    result))))
          (is (= 4 (count (jdbc/execute! ds ["select * from fruit"]))))
          (with-open [con (jdbc/get-connection ds)]
            (let [ac (.getAutoCommit con)]
              (is (= [{:next.jdbc/update-count 1}]
                    (jdbc/with-transaction [t con]
                      (let [save-point (.setSavepoint t (name (gensym)))
                            result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                        (.rollback t save-point)
                        result))))
              (is (= 4 (count (jdbc/execute! con ["select * from fruit"]))))
              (is (= ac (.getAutoCommit con))))))))
    (testing "c3p0 and SavePoints"
      (with-open [^PooledDataSource ds (c/->pool ComboPooledDataSource (db))]
        (testing "with-transaction with unnamed save point"
          (is (= [{:next.jdbc/update-count 1}]
                (jdbc/with-transaction [t ds]
                  (let [save-point (.setSavepoint t)
                        result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                    (.rollback t save-point)
                    result))))
          (is (= 4 (count (jdbc/execute! ds ["select * from fruit"]))))
          (with-open [con (jdbc/get-connection ds)]
            (let [ac (.getAutoCommit con)]
              (is (= [{:next.jdbc/update-count 1}]
                    (jdbc/with-transaction [t con]
                      (let [save-point (.setSavepoint t)
                            result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                        (.rollback t save-point)
                        result))))
              (is (= 4 (count (jdbc/execute! con ["select * from fruit"]))))
              (is (= ac (.getAutoCommit con))))))
        (testing "with-transaction with named save point"
          (is (= [{:next.jdbc/update-count 1}]
                (jdbc/with-transaction [t ds]
                  (let [save-point (.setSavepoint t (name (gensym)))
                        result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                    (.rollback t save-point)
                    result))))
          (is (= 4 (count (jdbc/execute! ds ["select * from fruit"]))))
          (with-open [con (jdbc/get-connection ds)]
            (let [ac (.getAutoCommit con)]
              (is (= [{:next.jdbc/update-count 1}]
                    (jdbc/with-transaction [t con]
                      (let [save-point (.setSavepoint t (name (gensym)))
                            result (jdbc/execute! t ["
      INSERT INTO fruit (name, appearance, cost, grade)
      VALUES ('Pear', 'green', 49, 47)
      "])]
                        (.rollback t save-point)
                        result))))
              (is (= 4 (count (jdbc/execute! con ["select * from fruit"]))))
              (is (= ac (.getAutoCommit con))))))))))