Last active
February 2, 2024 19:47
-
-
Save zelark/3b484e9b16ad55c97b4ed6f6ea13986b to your computer and use it in GitHub Desktop.
Support json and jsonb Postgres types in Clojure.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; For supporting more PG types, see https://github.com/remodoy/clj-postgresql | |
(ns pg-test.types | |
(:require [cheshire.core :as json] | |
[clojure.java.jdbc :as jdbc]) | |
(:import [org.postgresql.util PGobject] | |
[java.sql PreparedStatement])) | |
;; Writing | |
(defn- to-pg-json [data json-type] | |
(doto (PGobject.) | |
(.setType (name json-type)) | |
(.setValue (json/generate-string data)))) | |
(defn parameter-dispatch-fn [_ type-name] | |
(keyword type-name)) | |
(defmulti map->parameter parameter-dispatch-fn) | |
(defmethod map->parameter :json | |
[m _] | |
(to-pg-json m :json)) | |
(defmethod map->parameter :jsonb | |
[m _] | |
(to-pg-json m :jsonb)) | |
(extend-protocol jdbc/ISQLParameter | |
;; Convert Clojure maps to SQL parameter values | |
clojure.lang.IPersistentMap | |
(set-parameter [m ^PreparedStatement s ^long i] | |
(let [meta (.getParameterMetaData s)] | |
(if-let [type-name (keyword (.getParameterTypeName meta i))] | |
(.setObject s i (map->parameter m type-name)) | |
(.setObject s i m))))) | |
;; Reading | |
(defmulti read-pgobject | |
"Convert returned PGobject to Clojure value." | |
#(keyword (when (some? %) (.getType ^PGobject %)))) | |
(defmethod read-pgobject :json | |
[^PGobject x] | |
(when-let [val (.getValue x)] | |
(json/parse-string val true))) | |
(defmethod read-pgobject :jsonb | |
[^PGobject x] | |
(when-let [val (.getValue x)] | |
(json/parse-string val true))) | |
(defmethod read-pgobject :default | |
[^PGobject x] | |
(.getValue x)) | |
;; Extend clojure.java.jdbc's protocol for interpreting ResultSet column values. | |
(extend-protocol jdbc/IResultSetReadColumn | |
;; PGobjects have their own multimethod | |
PGobject | |
(result-set-read-column [val _ _] | |
(read-pgobject val))) | |
;; How to use: | |
;; (require 'pg-test.types) | |
;; (require '[clojure.java.jdbc :as jdbc]) | |
;; | |
;; (jdbc/query conn ["select data::json from testing"]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks, this helped a lot!