106 lines
4.6 KiB
Clojure
106 lines
4.6 KiB
Clojure
;; copyright (c) 2019-2021 Sean Corfield, all rights reserved
|
|
|
|
(ns next.jdbc.date-time
|
|
"Optional namespace that extends `next.jdbc.prepare/SettableParameter`
|
|
to various date/time types so that they will all be treated as SQL
|
|
timestamps (which also supports date and time column types) and has
|
|
functions to extend `next.jdbc.result-set/ReadableColumn`.
|
|
|
|
Simply requiring this namespace will extend the `SettableParameter` protocol
|
|
to the four types listed below.
|
|
|
|
In addition, there are several `read-as-*` functions here that will
|
|
extend `next.jdbc.result-set/ReadableColumn` to allow `java.sql.Date`
|
|
and `java.sql.Timestamp` columns to be read as (converted to) various
|
|
Java Time types automatically. The expectation is that you will call at
|
|
most one of these, at application startup, to enable the behavior you want.
|
|
|
|
Database support for Java Time:
|
|
* H2 and SQLite support conversion of Java Time (`Instant`, `LocalDate`,
|
|
`LocalDateTime`) out of the box,
|
|
* Nearly all databases support conversion of `java.util.Date` out of
|
|
the box -- except PostgreSQL apparently!
|
|
|
|
Types supported by this namespace:
|
|
* `java.time.Instant`
|
|
* `java.time.LocalDate`
|
|
* `java.time.LocalDateTime`
|
|
* `java.util.Date` -- mainly for PostgreSQL
|
|
|
|
PostgreSQL does not seem able to convert `java.util.Date` to a SQL
|
|
timestamp by default (every other database can!) so you'll probably
|
|
need to require this namespace, even if you don't use Java Time, when
|
|
working with PostgreSQL."
|
|
(:require [next.jdbc.prepare :as p]
|
|
[next.jdbc.result-set :as rs])
|
|
(:import (java.sql PreparedStatement Timestamp)))
|
|
|
|
(set! *warn-on-reflection* true)
|
|
|
|
(extend-protocol p/SettableParameter
|
|
;; Java Time type conversion:
|
|
java.time.Instant
|
|
(set-parameter [^java.time.Instant v ^PreparedStatement s ^long i]
|
|
(.setTimestamp s i (Timestamp/from v)))
|
|
java.time.LocalDate
|
|
(set-parameter [^java.time.LocalDate v ^PreparedStatement s ^long i]
|
|
(.setTimestamp s i (Timestamp/valueOf (.atStartOfDay v))))
|
|
java.time.LocalDateTime
|
|
(set-parameter [^java.time.LocalDateTime v ^PreparedStatement s ^long i]
|
|
(.setTimestamp s i (Timestamp/valueOf v)))
|
|
|
|
;; this is just to help PostgreSQL:
|
|
java.util.Date
|
|
(set-parameter [^java.util.Date v ^PreparedStatement s ^long i]
|
|
(.setTimestamp s i (Timestamp/from (.toInstant v))))
|
|
;; but avoid unnecessary conversions for SQL Date and Timestamp:
|
|
java.sql.Date
|
|
(set-parameter [^java.sql.Date v ^PreparedStatement s ^long i]
|
|
(.setDate s i v))
|
|
java.sql.Timestamp
|
|
(set-parameter [^java.sql.Timestamp v ^PreparedStatement s ^long i]
|
|
(.setTimestamp s i v)))
|
|
|
|
(defn read-as-instant
|
|
"After calling this function, `next.jdbc.result-set/ReadableColumn`
|
|
will be extended to (`java.sql.Date` and) `java.sql.Timestamp` so that any
|
|
timestamp columns will automatically be read as `java.time.Instant`.
|
|
|
|
Note that `java.sql.Date` columns will still be returns as-is because they
|
|
cannot be converted to an instant (they lack a time component)."
|
|
[]
|
|
(extend-protocol rs/ReadableColumn
|
|
java.sql.Date
|
|
(read-column-by-label [^java.sql.Date v _] 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-index [^java.sql.Timestamp v _2 _3] (.toInstant v))))
|
|
|
|
(defn read-as-local
|
|
"After calling this function, `next.jdbc.result-set/ReadableColumn`
|
|
will be extended to `java.sql.Date` and `java.sql.Timestamp` so that any
|
|
date or timestamp columns will automatically be read as `java.time.LocalDate`
|
|
or `java.time.LocalDateTime` respectively."
|
|
[]
|
|
(extend-protocol rs/ReadableColumn
|
|
java.sql.Date
|
|
(read-column-by-label [^java.sql.Date v _] (.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-index [^java.sql.Timestamp v _2 _3] (.toLocalDateTime v))))
|
|
|
|
(defn read-as-default
|
|
"After calling this function, `next.jdbc.result-set/ReadableColumn`
|
|
will be extended to `java.sql.Date` and `java.sql.Timestamp` so that any
|
|
date or timestamp columns will be read as-is. This is provided for
|
|
completeness, to undo the effects of `read-as-instant` or `read-as-local`."
|
|
[]
|
|
(extend-protocol rs/ReadableColumn
|
|
java.sql.Date
|
|
(read-column-by-label [^java.sql.Date v _] 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-index [^java.sql.Timestamp v _2 _3] v)))
|