new database
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
(ns kit.edge.db.postgres
|
||||
(:require
|
||||
[cheshire.core :as cheshire]
|
||||
[next.jdbc]
|
||||
[next.jdbc.prepare :as prepare]
|
||||
[next.jdbc.result-set :as result-set])
|
||||
(:import
|
||||
[clojure.lang IPersistentMap IPersistentVector]
|
||||
[java.sql Array PreparedStatement Timestamp]
|
||||
[java.time Instant LocalDate LocalDateTime]
|
||||
[org.postgresql.util PGobject]))
|
||||
|
||||
(def ->json cheshire/generate-string)
|
||||
(def <-json #(cheshire/parse-string % true))
|
||||
|
||||
(defn ->pgobject
|
||||
"Transforms Clojure data to a PGobject that contains the data as
|
||||
JSON. PGObject type defaults to `jsonb` but can be changed via
|
||||
metadata key `:pgtype`"
|
||||
[x]
|
||||
(let [pgtype (:pgtype (meta x) "jsonb")]
|
||||
(doto (PGobject.)
|
||||
(.setType pgtype)
|
||||
(.setValue (->json x)))))
|
||||
|
||||
(defn <-pgobject
|
||||
"Transform PGobject containing `json` or `jsonb` value to Clojure data"
|
||||
[^PGobject v]
|
||||
(let [type (.getType v)
|
||||
value (.getValue v)]
|
||||
(if (#{"jsonb" "json"} type)
|
||||
(when value
|
||||
(with-meta (<-json value) {:pgtype type}))
|
||||
value)))
|
||||
|
||||
(extend-protocol result-set/ReadableColumn
|
||||
Array
|
||||
(read-column-by-label [^Array v _] (vec (.getArray v)))
|
||||
(read-column-by-index [^Array v _2 _3] (vec (.getArray v)))
|
||||
|
||||
PGobject
|
||||
(read-column-by-label [^PGobject v _] (<-pgobject v))
|
||||
(read-column-by-index [^PGobject v _2 _3] (<-pgobject v)))
|
||||
|
||||
(extend-protocol prepare/SettableParameter
|
||||
Instant
|
||||
(set-parameter [^Instant v ^PreparedStatement ps ^long i]
|
||||
(.setTimestamp ps i (Timestamp/from v)))
|
||||
|
||||
LocalDate
|
||||
(set-parameter [^LocalDate v ^PreparedStatement ps ^long i]
|
||||
(.setTimestamp ps i (Timestamp/valueOf (.atStartOfDay v))))
|
||||
|
||||
LocalDateTime
|
||||
(set-parameter [^LocalDateTime v ^PreparedStatement ps ^long i]
|
||||
(.setTimestamp ps i (Timestamp/valueOf v)))
|
||||
|
||||
IPersistentMap
|
||||
(set-parameter [m ^PreparedStatement s i]
|
||||
(.setObject s i (->pgobject m)))
|
||||
|
||||
IPersistentVector
|
||||
(set-parameter [^clojure.lang.IPersistentVector v ^java.sql.PreparedStatement stmt ^long idx]
|
||||
(let [conn (.getConnection stmt)
|
||||
meta (.getParameterMetaData stmt)
|
||||
type-name (.getParameterTypeName meta idx)]
|
||||
(if-let [elem-type (when (= (first type-name) \_)
|
||||
(apply str (rest type-name)))]
|
||||
(.setObject stmt idx (.createArrayOf conn elem-type (to-array v)))
|
||||
(.setObject stmt idx (->pgobject v))))))
|
||||
@@ -0,0 +1,59 @@
|
||||
(ns kit.edge.db.sql.conman
|
||||
(:require
|
||||
[clojure.tools.logging :as log]
|
||||
[conman.core :as conman]
|
||||
[integrant.core :as ig]
|
||||
[kit.ig-utils :as ig-utils]))
|
||||
|
||||
(defmethod ig/init-key :db.sql/connection
|
||||
[_ pool-spec]
|
||||
(conman/connect! pool-spec))
|
||||
|
||||
(defmethod ig/suspend-key! :db.sql/connection [_ _])
|
||||
|
||||
(defmethod ig/halt-key! :db.sql/connection
|
||||
[_ conn]
|
||||
(conman/disconnect! conn))
|
||||
|
||||
(defmethod ig/resume-key :db.sql/connection
|
||||
[key opts old-opts old-impl]
|
||||
(ig-utils/resume-handler key opts old-opts old-impl))
|
||||
|
||||
(defn queries-dev [load-queries]
|
||||
(fn
|
||||
([query params]
|
||||
(conman/query (load-queries) query params))
|
||||
([conn query params & opts]
|
||||
(conman/query conn (load-queries) query params opts))))
|
||||
|
||||
(defn queries-prod [load-queries]
|
||||
(let [queries (load-queries)]
|
||||
(fn
|
||||
([query params]
|
||||
(conman/query queries query params))
|
||||
([conn query params & opts]
|
||||
(conman/query conn queries query params opts)))))
|
||||
|
||||
(defmethod ig/init-key :db.sql/query-fn
|
||||
[_ {:keys [conn options filename filenames env]
|
||||
:or {options {}}}]
|
||||
(let [filenames (or filenames [filename])
|
||||
load-queries #(apply conman/bind-connection-map conn options filenames)]
|
||||
(with-meta
|
||||
(if (= env :dev)
|
||||
(queries-dev load-queries)
|
||||
(queries-prod load-queries))
|
||||
{:mtimes (mapv ig-utils/last-modified filenames)})))
|
||||
|
||||
(defmethod ig/suspend-key! :db.sql/query-fn [_ _])
|
||||
|
||||
(defmethod ig/resume-key :db.sql/query-fn
|
||||
[k {:keys [filename filenames] :as opts} old-opts old-impl]
|
||||
(let [check-res (and (= opts old-opts)
|
||||
(= (mapv ig-utils/last-modified (or filenames [filename]))
|
||||
(:mtimes (meta old-impl))))]
|
||||
(log/info k "resume check. Same?" check-res)
|
||||
(if check-res
|
||||
old-impl
|
||||
(do (ig/halt-key! k old-impl)
|
||||
(ig/init-key k opts)))))
|
||||
Reference in New Issue
Block a user