Fork me on GitHub
#sql
<
2024-05-16
>
rgm15:05:38

I'm trying to test a library that involves stuffing data into a JSONB column. I tried to avoid making assumptions about whether or not a user has extended SettableParameter and Readable column as documented in the next.jdbc Tips & Tricks. So internally I'm thinking I just check if I have a clojure type or not coming back from the DB. But in my tests (against a real psql instance) ... is it possible to both extend the protocol and, er, "de-extend" it to get coverage on both cases? Seems like this is at a JVM-level and not a datasource level.

rgm15:05:18

I guess I could test without extending the protocols first, then extend them, then test again, but the test order dependency seems a bit declassé.

rgm14:05:06

Ah, I figured out something that will work that I can do at a per-test level:

(def ^:dynamic *serialize*? false)

(defn clj->pgobject [x]
  (if *serialize?*
    (let [pgtype (or (:pgtype (meta x)) "jsonb")]
      (doto (PGobject.)
        (.setType pgtype)
        (.setValue (x->json x))))
    x))

(defn init-json-write-helper []
  ;; if a SQL parameter is a Clojure hash map or vector, it'll be transformed
  ;; to a PGobject for JSON/JSONB:
  (extend-protocol next.jdbc.prepare/SettableParameter
    clojure.lang.IPersistentMap
    (set-parameter [m ^PreparedStatement s i]
      (.setObject s i (clj->pgobject m)))

    clojure.lang.IPersistentVector
    (set-parameter [v ^PreparedStatement s i]
      (.setObject s i (clj->pgobject v)))))


(binding [*serialize?* true]
   ;; do the test involving serialization
  )

1
sheluchin16:05:43

Small issue in the docs: https://cljdoc.org/d/com.github.seancorfield/next.jdbc/1.3.925/doc/all-the-options?q=%3Aschema-opts#datafying--navigating-rows-and-result-sets the link in See datafy, nav, and :schema for more details. takes you to a GitHub 404.

seancorfield16:05:28

Can you open a GitHub issue so this doesn't get forgotten?

seancorfield16:05:14

Much appreciated.

👍 1
sheluchin16:05:54

Is there a way to get nav to play nice with rs/as-kebab-maps? It looks like _ is accepted and optional, but when your result set uses -id instead, nav'ing doesn't work.

seancorfield19:05:50

That's what the recently-added :schema-opts stuff is for... but maybe you can provide more detail of what you expected to work and what the actual behavior was?

sheluchin19:05:36

I think if I use {:schema-opts {:fk-suffix "id" :pk "did"}} but my foreign keys look like :foo-id it will not work because it's expecting :foo_id. Does that make sense, or maybe I'm missing something? > For :fk-suffix, the is still permitted and optional in the column name, so if you specified :schema-opts {:fk-suffix "fk"} then addressfk and addressfk would both be treated as foreign keys into the address table. but no mention of address-fk which is what the field names would show up like in the REPL if rs/as-kebab-maps is used.

seancorfield19:05:40

Can you open a GH issue with details? It may be straightforward to make this work...

seancorfield20:05:53

Yeah, I think this could be a one-line change (to the regex on line 1040 of result_set.clj) and some doc updates.

rgm14:05:06

Ah, I figured out something that will work that I can do at a per-test level:

(def ^:dynamic *serialize*? false)

(defn clj->pgobject [x]
  (if *serialize?*
    (let [pgtype (or (:pgtype (meta x)) "jsonb")]
      (doto (PGobject.)
        (.setType pgtype)
        (.setValue (x->json x))))
    x))

(defn init-json-write-helper []
  ;; if a SQL parameter is a Clojure hash map or vector, it'll be transformed
  ;; to a PGobject for JSON/JSONB:
  (extend-protocol next.jdbc.prepare/SettableParameter
    clojure.lang.IPersistentMap
    (set-parameter [m ^PreparedStatement s i]
      (.setObject s i (clj->pgobject m)))

    clojure.lang.IPersistentVector
    (set-parameter [v ^PreparedStatement s i]
      (.setObject s i (clj->pgobject v)))))


(binding [*serialize?* true]
   ;; do the test involving serialization
  )

1