From fed6e671f9778f95374944999216806c63a03e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Snorre=20Magnus=20Dav=C3=B8en?= Date: Sun, 25 Apr 2021 13:35:20 +0200 Subject: [PATCH] Document PGInterval to Duration handling for postgres MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Postgres supports a non-standard Interval type which is implemented as the PGInterval type in the postgres jdbc driver. Many users would likely want to deal with intervals as the standard java.time.Duration type. How this can be done is documented under tips & tricks. Signed-off-by: Snorre Magnus Davøen --- doc/tips-and-tricks.md | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/doc/tips-and-tricks.md b/doc/tips-and-tricks.md index 420fdfe..c00662e 100644 --- a/doc/tips-and-tricks.md +++ b/doc/tips-and-tricks.md @@ -202,6 +202,54 @@ In addition, if you want `java.time.Instant`, `java.time.LocalDate`, and `java.t `next.jdbc.date-time` also includes functions that you can call at application startup to extend `ReadableColumn` to either return `java.time.Instant` or `java.time.LocalDate`/`java.time.LocalDateTime` (as well as a function to restore the default behavior of returning `java.sql.Date` and `java.sql.Timestamp`). +### Working with Interval + +Postgres has a nonstandard SQL type Interval that is implemented in the Postgres driver as the `org.postgresql.util.PGInterval` type. +In many cases you would want to work with intervals as `java.time.Duration` type by default. + +You can support `Duration` instances by extending `SettableParameter` to the `java.time.Duration` type. +Conversely you can support converting PGIntervals back to Durations by extending `ReadableColumn` to the `org.postgresql.util.PGInterval` type. + +```clojure +(import '[org.postgresql.util PGInterval]) +(import '[java.sql PreparedStatement]) +(import '[java.time Duration]) +(require '[next.jdbc.result-set :as rs]) +(require '[next.jdbc.prepare :as p]) + +(defn ->pg-interval + "Takes a Dudration instance and converts it into a PGInterval + instance where the interval is created as a number of seconds." + [^java.time.Duration duration] + (doto (PGInterval.) + (.setSeconds (.getSeconds duration)))) + +(extend-protocol p/SettableParameter + ;; Convert durations to PGIntervals before inserting into db + java.time.Duration + (set-parameter [^java.time.Duration v ^PreparedStatement s ^long i] + (.setObject s i (->pg-interval v)))) + + +(defn <-pg-interval + "Takes a PGInterval instance and converts it into a Duration + instance. Ignore sub-second units." + [^org.postgresql.util.PGInterval interval] + (-> Duration/ZERO + (.plusSeconds (.getSeconds interval)) + (.plusMinutes (.getMinutes interval)) + (.plusHours (.getHours interval)) + (.plusDays (.getDays interval)))) + +(extend-protocol rs/ReadableColumn + ;; Convert PGIntervals back to durations + org.postgresql.util.PGInterval + (read-column-by-label [^org.postgresql.util.PGInterval v _] + (<-pg-interval v)) + (read-column-by-index [^org.postgresql.util.PGInterval v _2 _3] + (<-pg-interval v))) +``` + ### Working with Enumerated Types PostgreSQL has a SQL extension for defining enumerated types and the default `set-parameter` implementation will not work for those. You can use `next.jdbc.types/as-other` to wrap string values in a way that the JDBC driver will convert them to enumerated type values: