(ns shapey-shifty.db.core (:require [cheshire.core :refer [generate-string parse-string]] [clojure.java.jdbc :as jdbc] [clojure.tools.logging :as log] [conman.core :as conman] [java-time :as jt] [java-time.pre-java8] [shapey-shifty.config :refer [env]] [mount.core :refer [defstate]]) (:import org.postgresql.util.PGobject java.sql.Array clojure.lang.IPersistentMap clojure.lang.IPersistentVector [java.sql BatchUpdateException PreparedStatement])) (defstate ^:dynamic *db* :start (if-let [jdbc-url (env :database-url)] (conman/connect! {:jdbc-url jdbc-url}) (do (log/warn "database connection URL was not found, please set :database-url in your config, e.g: dev-config.edn") *db*)) :stop (conman/disconnect! *db*)) (conman/bind-connection *db* "sql/queries.sql") (extend-protocol jdbc/IResultSetReadColumn java.sql.Timestamp (result-set-read-column [v _2 _3] (.toLocalDateTime v)) java.sql.Date (result-set-read-column [v _2 _3] (.toLocalDate v)) java.sql.Time (result-set-read-column [v _2 _3] (.toLocalTime v)) Array (result-set-read-column [v _ _] (vec (.getArray v))) PGobject (result-set-read-column [pgobj _metadata _index] (let [type (.getType pgobj) value (.getValue pgobj)] (case type "json" (parse-string value true) "jsonb" (parse-string value true) "citext" (str value) value)))) (defn to-pg-json [value] (doto (PGobject.) (.setType "jsonb") (.setValue (generate-string value)))) (extend-type clojure.lang.IPersistentVector jdbc/ISQLParameter (set-parameter [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 (to-pg-json v)))))) (extend-protocol jdbc/ISQLValue java.util.Date (sql-value [v] (java.sql.Timestamp. (.getTime v))) java.time.LocalTime (sql-value [v] (jt/sql-time v)) java.time.LocalDate (sql-value [v] (jt/sql-date v)) java.time.LocalDateTime (sql-value [v] (jt/sql-timestamp v)) java.time.ZonedDateTime (sql-value [v] (jt/sql-timestamp v)) IPersistentMap (sql-value [value] (to-pg-json value)) IPersistentVector (sql-value [value] (to-pg-json value)))