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: