Back

builder-adapter (clj)

(source)

function

(builder-adapter builder-fn column-by-index-fn)
Given any builder function (e.g., `as-lower-maps`) and a column reading function, return a new builder function that uses that column reading function instead of `.getObject` and `read-column-by-index` so you can override the default behavior. The default column-by-index-fn behavior would be equivalent to: (defn default-column-by-index-fn [builder ^ResultSet rs ^Integer i] (read-column-by-index (.getObject rs i) (:rsmeta builder) i)) Your column-by-index-fn can use the result set metadata `(:rsmeta builder)` and/or the (processed) column name `(nth (:cols builder) (dec i))` to determine whether to call `.getObject` or some other method to read the column's value, and can choose whether or not to use the `ReadableColumn` protocol-based value processor (and could add metadata to the value to satisfy that protocol on a per-instance basis).

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 bool-tests
  (doseq [[n b] [["zero" 0] ["one" 1] ["false" false] ["true" true]]
          :let [v-bit  (if (number? b) b (if b 1 0))
                v-bool (if (number? b) (pos? b) b)]]
    (jdbc/execute-one!
     (ds)
     ["insert into btest (name,is_it,twiddle) values (?,?,?)"
      n
      (if (postgres?)
        (types/as-boolean b)
        b) ; 0, 1, false, true are all acceptable
      (cond (hsqldb?)
            v-bool ; hsqldb requires a boolean here
            (postgres?)
            (types/as-other v-bit) ; really postgres??
            :else
            v-bit)]))
  (let [data (jdbc/execute! (ds) ["select * from btest"]
                            (default-options))]
    (if (sqlite?)
      (is (every? number?  (map (column :BTEST/IS_IT) data)))
      (is (every? boolean? (map (column :BTEST/IS_IT) data))))
    (if (or (sqlite?) (derby?))
      (is (every? number?  (map (column :BTEST/TWIDDLE) data)))
      (is (every? boolean? (map (column :BTEST/TWIDDLE) data)))))
  (let [data (jdbc/execute! (ds) ["select * from btest"]
                            (cond-> (default-options)
                              (sqlite?)
                              (assoc :builder-fn
                                     (rs/builder-adapter
                                      rs/as-maps
                                      (fn [builder ^ResultSet rs ^Integer i]
                                        (let [rsm ^ResultSetMetaData (:rsmeta builder)]
                                          (rs/read-column-by-index
                                           ;; we only use bit and bool for
                                           ;; sqlite (not boolean)
                                           (if (#{"BIT" "BOOL"} (.getColumnTypeName rsm i))
                                             (.getBoolean rs i)
                                             (.getObject rs i))
                                           rsm
                                           i)))))))]
    (is (every? boolean? (map (column :BTEST/IS_IT) data)))
    (if (derby?)
      (is (every? number?  (map (column :BTEST/TWIDDLE) data)))
      (is (every? boolean? (map (column :BTEST/TWIDDLE) data)))))
  (let [data (reduce (fn [acc row]
                       (conj acc (cond-> (select-keys row [:is_it :twiddle])
                                   (sqlite?)
                                   (update :is_it pos?)
                                   (or (sqlite?) (derby?))
                                   (update :twiddle pos?))))
                     []
                     (jdbc/plan (ds) ["select * from btest"]))]
    (is (every? boolean? (map :is_it data)))
    (is (every? boolean? (map :twiddle data)))))
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 bool-tests
  (doseq [[n b] [["zero" 0] ["one" 1] ["false" false] ["true" true]]
          :let [v-bit  (if (number? b) b (if b 1 0))
                v-bool (if (number? b) (pos? b) b)]]
    (jdbc/execute-one!
     (ds)
     ["insert into btest (name,is_it,twiddle) values (?,?,?)"
      n
      (if (postgres?)
        (types/as-boolean b)
        b) ; 0, 1, false, true are all acceptable
      (cond (hsqldb?)
            v-bool ; hsqldb requires a boolean here
            (postgres?)
            (types/as-other v-bit) ; really postgres??
            :else
            v-bit)]))
  (let [data (jdbc/execute! (ds) ["select * from btest"]
                            (default-options))]
    (if (sqlite?)
      (is (every? number?  (map (column :BTEST/IS_IT) data)))
      (is (every? boolean? (map (column :BTEST/IS_IT) data))))
    (if (or (sqlite?) (derby?))
      (is (every? number?  (map (column :BTEST/TWIDDLE) data)))
      (is (every? boolean? (map (column :BTEST/TWIDDLE) data)))))
  (let [data (jdbc/execute! (ds) ["select * from btest"]
                            (cond-> (default-options)
                              (sqlite?)
                              (assoc :builder-fn
                                     (rs/builder-adapter
                                      rs/as-maps
                                      (fn [builder ^ResultSet rs ^Integer i]
                                        (let [rsm ^ResultSetMetaData (:rsmeta builder)]
                                          (rs/read-column-by-index
                                           ;; we only use bit and bool for
                                           ;; sqlite (not boolean)
                                           (if (#{"BIT" "BOOL"} (.getColumnTypeName rsm i))
                                             (.getBoolean rs i)
                                             (.getObject rs i))
                                           rsm
                                           i)))))))]
    (is (every? boolean? (map (column :BTEST/IS_IT) data)))
    (if (derby?)
      (is (every? number?  (map (column :BTEST/TWIDDLE) data)))
      (is (every? boolean? (map (column :BTEST/TWIDDLE) data)))))
  (let [data (reduce (fn [acc row]
                       (conj acc (cond-> (select-keys row [:is_it :twiddle])
                                   (sqlite?)
                                   (update :is_it pos?)
                                   (or (sqlite?) (derby?))
                                   (update :twiddle pos?))))
                     []
                     (jdbc/plan (ds) ["select * from btest"]))]
    (is (every? boolean? (map :is_it data)))
    (is (every? boolean? (map :twiddle data)))))