Inserting PostgreSQL arrays with Clojure

后端 未结 3 1209
情话喂你
情话喂你 2021-02-04 10:25

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 ki

相关标签:
3条回答
  • 2021-02-04 10:42

    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> (def db (clj-postgresql.core/pool :dbname "test"))
    #'user/db
    user> (clojure.java.jdbc/query db ["SELECT ?::text[], ?::int[]" ["foo" "bar"] [1 2 3]])
    ({:int4 [1 2 3], :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

    0 讨论(0)
  • 2021-02-04 10:53

    A similar strategy that I've been using:

    (defn vec->arr [array-vector]
      (.createArrayOf (j/get-connection db) "varchar" (into-array String array-vector)))
    
    (extend-protocol j/ISQLValue
        clojure.lang.IPersistentVector
        (sql-value [v]
        (vec->arr v)))
    
    0 讨论(0)
  • 2021-02-04 10:57

    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

    (def con (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\"}')"])
    
    0 讨论(0)
提交回复
热议问题