Skip to content Skip to sidebar Skip to footer

Inserting Postgresql Arrays With Clojure

I can't find a way to insert Postgres' array type with Clojure. (sql/insert! db :things {:animals ['cow' 'pig']}) Didn't work which I kind of expected. Error message: PSQLExceptio

Solution 1:

You can make clojure.java.jdbc automatically convert between Clojure vectors and SQL arrays by extending two protocols. This can be done from your own code:

(extend-protocol clojure.java.jdbc/ISQLParameter
  clojure.lang.IPersistentVector
  (set-parameter [v ^java.sql.PreparedStatement stmt ^long i]
    (let [conn (.getConnection stmt)
          meta (.getParameterMetaData stmt)
          type-name (.getParameterTypeName meta i)]
      (if-let [elem-type (when (= (first type-name) \_) (apply str (rest type-name)))]
        (.setObject stmt i (.createArrayOf conn elem-type (to-array v)))
        (.setObject stmt i v)))))

(extend-protocol clojure.java.jdbc/IResultSetReadColumn
  java.sql.Array
  (result-set-read-column [val _ _]
    (into [] (.getArray val))))

REPL Example:

user> (defdb(clj-postgresql.core/pool :dbname"test"))
#'user/db
user> (clojure.java.jdbc/query db ["SELECT ?::text[], ?::int[]" ["foo""bar"] [123]])
({:int4 [123], :text ["foo""bar"]})

I'm currently working on a library that will support PostgreSQL, and PostGIS types automatically. It's still very much work in process though https://github.com/remodoy/clj-postgresql

Solution 2:

to use insert! to insert a vector of strings you must create an object (from the vector of strings) that implements java.sql.Array. You can use java.sql.Connection.createArrayOf to create such object

(defcon(sql/get-connection db))

(def val-to-insert 
    (.createArrayOf con "varchar" (into-array String ["cow", "pig"]))

(sql/insert! db :things {:animals val-to-insert})

and

clojure.java.jdbc's docs on execute! said

(execute! db-spec [sql& params] :multi? false :transaction? true)
(execute! db-spec [sql& param-groups] :multi? true :transaction? true)

Your must put your sql string in a vector to make it work.

(sql/execute! db ["INSERT INTO things (animals) VALUES ('{\"cow\", \"pig\"}')"])

Solution 3:

A similar strategy that I've been using:

(defn vec->arr [array-vector]
  (.createArrayOf (j/get-connection db) "varchar" (into-arrayStringarray-vector)))

(extend-protocol j/ISQLValue
    clojure.lang.IPersistentVector
    (sql-value [v]
    (vec->arr v)))

Post a Comment for "Inserting Postgresql Arrays With Clojure"