-
Notifications
You must be signed in to change notification settings - Fork 0
/
conv.clj
61 lines (55 loc) · 2.39 KB
/
conv.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
(ns utility-belt.sql.conv
(:require [clojure.java.jdbc :as jdbc]
[cheshire.core :as json]
[clj-time.coerce :as coerce])
(:import (org.postgresql.util PGobject)
(java.sql PreparedStatement)
(org.postgresql.jdbc PgArray)))
(extend-protocol jdbc/IResultSetReadColumn
org.postgresql.jdbc.PgArray
(result-set-read-column [val metadata _]
(vec (.getArray val)))
;; When reading JSONB, parse it out to clojure structure
PGobject
(result-set-read-column [pgobj metadata idx]
(let [type (.getType ^PGobject pgobj)
value (.getValue ^PGobject pgobj)]
(case type
"json" (json/parse-string value true)
"jsonb" (json/parse-string value true)
value)))
;; When reading timestamp, parse it out to java datetime
java.sql.Timestamp
(result-set-read-column [pgobj metadata idx]
(coerce/to-date-time pgobj)))
(defn value-to-json-pgobject [value]
(doto (PGobject.)
(.setType "jsonb")
(.setValue (json/generate-string value))))
(extend-protocol jdbc/ISQLValue
;; When inserting clojure structure convert it to JSONB
clojure.lang.IPersistentMap
(sql-value [value] (value-to-json-pgobject value))
clojure.lang.IPersistentVector
(sql-value [value] (value-to-json-pgobject value))
;; When inserting datetime convert it to sql timestamp
org.joda.time.DateTime
(sql-value [value]
(coerce/to-sql-time value)))
(extend-protocol jdbc/ISQLParameter
clojure.lang.IPersistentVector
(set-parameter [v ^PreparedStatement s ^long i]
;; Adapted from
;; https://github.com/remodoy/clj-postgresql/blob/78a3d11376f0991d92e6faf7d0287ed74df3521e/src/clj_postgresql/types.clj#L133
;; Get the current connection and get the parameter's metadata
;; so we can inspect the type expected by psql
(let [conn (.getConnection s)
meta (.getParameterMetaData s)
type-name (.getParameterTypeName meta i)]
;; if we found a type, remove the underscore so we match a native type
;; and create an array of elem-type
;; otherwise fallback to original implementation of clojure.java.jdbc
;; https://github.com/clojure/java.jdbc/blob/master/src/main/clojure/clojure/java/jdbc.clj#L471
(if-let [elem-type (when type-name (second (re-find #"^_(.*)" type-name)))]
(.setObject s i (.createArrayOf conn elem-type (to-array v)))
(.setObject s i (jdbc/sql-value v))))))