/
date_time.clj
106 lines (93 loc) · 4.56 KB
/
date_time.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
;; copyright (c) 2019-2020 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)))