Extend ReadableColumn protocol with more rsmeta

There is a use case for needing access to ResultSetMetaData inside
read-column-by-label.

SQLite doesn't have a boolean affinity. It stores booleans as integers 0
or 1, so that's what the JDBC driver gives us, and without access to
ResultSetMetaData we have no way of knowing the intended affinity of the column
that the value came from. But by looking at `getColumnTypeName` on the
ResultSetMetaData and seeing if it's "BOOL", we can perform the
conversion in the ReadableColumn implementations.
This commit is contained in:
Eric Ihli 2020-07-21 12:40:18 -07:00
parent 3143cd1acd
commit c27e9a57e0
4 changed files with 26 additions and 3 deletions

View file

@ -138,11 +138,15 @@ The default implementation of this protocol is for these two functions to return
java.sql.Date
(read-column-by-label [^java.sql.Date v _]
(.toLocalDate v))
(read-column-by-label [^java.sql.Date v _2 _3]
(.toLocalDate v))
(read-column-by-index [^java.sql.Date v _2 _3]
(.toLocalDate v))
java.sql.Timestamp
(read-column-by-label [^java.sql.Timestamp v _]
(.toInstant v))
(read-column-by-label [^java.sql.Timestamp v _2 _3]
(.toInstant v))
(read-column-by-index [^java.sql.Timestamp v _2 _3]
(.toInstant v)))
```

View file

@ -11,6 +11,8 @@ Columns declared with the `CLOB` or `BLOB` SQL types are typically rendered into
java.sql.Clob
(read-column-by-label [^java.sql.Clob v _]
(with-open [rdr (.getCharacterStream v)] (slurp rdr)))
(read-column-by-label [^java.sql.Clob v _2 _3]
(with-open [rdr (.getCharacterStream v)] (slurp rdr)))
(read-column-by-index [^java.sql.Clob v _2 _3]
(with-open [rdr (.getCharacterStream v)] (slurp rdr))))
```
@ -22,6 +24,8 @@ There is a helper in `next.jdbc.result-set` to make this easier -- `clob->string
java.sql.Clob
(read-column-by-label [^java.sql.Clob v _]
(clob->string v))
(read-column-by-label [^java.sql.Clob v _2 _3_]
(clob->string v))
(read-column-by-index [^java.sql.Clob v _2 _3]
(clob->string v)))
```
@ -145,6 +149,7 @@ ResultSet protocol extension to read SQL arrays as Clojure vectors.
(extend-protocol rs/ReadableColumn
Array
(read-column-by-label [^Array v _] (vec (.getArray v)))
(read-column-by-label [^Array v _ _] (vec (.getArray v)))
(read-column-by-index [^Array v _ _] (vec (.getArray v))))
```
@ -272,6 +277,8 @@ Finally we extend `next.jdbc.prepare/SettableParameter` and `next.jdbc.result-se
org.postgresql.util.PGobject
(read-column-by-label [^org.postgresql.util.PGobject v _]
(<-pgobject v))
(read-column-by-label [^org.postgresql.util.PGobject v _2 _3]
(<-pgobject v))
(read-column-by-index [^org.postgresql.util.PGobject v _2 _3]
(<-pgobject v)))
```

View file

@ -72,9 +72,11 @@
(extend-protocol rs/ReadableColumn
java.sql.Date
(read-column-by-label [^java.sql.Date v _] v)
(read-column-by-label [^java.sql.Date v _2 _3] v)
(read-column-by-index [^java.sql.Date v _2 _3] v)
java.sql.Timestamp
(read-column-by-label [^java.sql.Timestamp v _] (.toInstant v))
(read-column-by-label [^java.sql.Timestamp v _2 _3] (.toInstant v))
(read-column-by-index [^java.sql.Timestamp v _2 _3] (.toInstant v))))
(defn read-as-local
@ -86,9 +88,11 @@
(extend-protocol rs/ReadableColumn
java.sql.Date
(read-column-by-label [^java.sql.Date v _] (.toLocalDate v))
(read-column-by-label [^java.sql.Date v _2 _3] (.toLocalDate v))
(read-column-by-index [^java.sql.Date v _2 _3] (.toLocalDate v))
java.sql.Timestamp
(read-column-by-label [^java.sql.Timestamp v _] (.toLocalDateTime v))
(read-column-by-label [^java.sql.Timestamp v _2 _3] (.toLocalDateTime v))
(read-column-by-index [^java.sql.Timestamp v _2 _3] (.toLocalDateTime v))))
(defn read-as-default
@ -100,7 +104,9 @@
(extend-protocol rs/ReadableColumn
java.sql.Date
(read-column-by-label [^java.sql.Date v _] v)
(read-column-by-label [^java.sql.Date v _2 _3] v)
(read-column-by-index [^java.sql.Date v _2 _3] v)
java.sql.Timestamp
(read-column-by-label [^java.sql.Timestamp v _] v)
(read-column-by-label [^java.sql.Timestamp v _2 _3] v)
(read-column-by-index [^java.sql.Timestamp v _2 _3] v)))

View file

@ -102,7 +102,9 @@
`Boolean` implementation ensures a canonicalized `true`/`false` value,
but it can be extended to provide custom behavior for special types.
Extension via metadata is supported."
(read-column-by-label [val label]
(read-column-by-label
[val label]
[val rsmeta label]
"Function for transforming values after reading them via a column label.")
(read-column-by-index [val rsmeta idx]
"Function for transforming values after reading them via a column index."))
@ -110,14 +112,17 @@
(extend-protocol ReadableColumn
Object
(read-column-by-label [x _] x)
(read-column-by-label [x _2 _3] x)
(read-column-by-index [x _2 _3] x)
Boolean
(read-column-by-label [x _] (if (= true x) true false))
(read-column-by-label [x _2 _3] (if (= true x) true false))
(read-column-by-index [x _2 _3] (if (= true x) true false))
nil
(read-column-by-label [_1 _2] nil)
(read-column-by-label [_1 _2 _3] nil)
(read-column-by-index [_1 _2 _3] nil))
(defprotocol RowBuilder
@ -513,6 +518,7 @@
(try
(clojure.lang.MapEntry. k (read-column-by-label
(.getObject rs (name k))
(:rsmeta @builder)
(name k)))
(catch SQLException _)))
@ -535,14 +541,14 @@
(if (number? k)
(let [^Integer i (inc k)]
(read-column-by-index (.getObject rs i) (:rsmeta @builder) i))
(read-column-by-label (.getObject rs (name k)) (name k)))
(read-column-by-label (.getObject rs (name k)) (:rsmeta @builder) (name k)))
(catch SQLException _)))
(valAt [this k not-found]
(try
(if (number? k)
(let [^Integer i (inc k)]
(read-column-by-index (.getObject rs i) (:rsmeta @builder) i))
(read-column-by-label (.getObject rs (name k)) (name k)))
(read-column-by-label (.getObject rs (name k)) (:rsmeta @builder) (name k)))
(catch SQLException _
not-found)))