Fork me on GitHub

Yep, the sample code in the docs is demonstrating a "Clojure in - Clojure out" use-case. However I think adding the when guard to the example would make sense to avoid confusion if for any reason there's a JSON null in the database. It's cool to see this kind of edge-cases that I've never personally encountered. 🙂


Will you @seancorfield update the docs? If you wish, I can also do that later today.


I'll do it right now, while it's fresh in my mind!

👍 3

Cool, thanks!


Update pushed. It'll get to when I make a new release (which likely won't be for a while).

🚀 3
Test This12:09:27

Thank you so much @seancorfield and @valtteri. I will try out the new example.


Hello, looking for an example of using next.jdbc snake-kebab-opts to convert hash-maps with kebab-case keys to a snake_case as part of the next.jdbc.sql/insert! function. I've tried different combinations to adding an options map to the insert! function, but haven't found the right syntax yet. I added so the docs suggest I dont need to provide a function, next.jdbc should convert it given the right option map, at least that's what I understood from the docs (which could be wrong) I have a specification that generates a hash-map with kebab-case keywords

;; => #:practicalli.specifications-banking{:account-holder-id
;;                                         #uuid "57e23f2a-e395-4af3-ba17-25bd741fe4ad",
;;                                         :first-name "59Z3vCS1L0pbhe17aF",
;;                                         :last-name "fKuQwcI1c7Ox2N2f1",
;;                                         :email-address
;;                                         "0x7jNK5sBrg52NPYt1pk8i3DqF",
;;                                         :residential-address "71DWd6kaN6DGy",
;;                                         :social-security-number
;;                                         "7g06UJEvyTaV6Pg2w694AsV42Yy"}
I can insert! using a hash-map
{:account_holder_id      (java.util.UUID/randomUUID)
 :first_name             "Rachel"
 :last_name              "Rocketpack"
 :email_address          ""
 :residential_address    "1 Ultimate Question Lane, Altar IV"
 :social_security_number "BB104312D"} 
However, using this function call to convert the keys from the spec to snake_case and insert...
(jdbc-sql/insert! db-specification-dev
                  {:column-fn next.jdbc/unqualified-snake-kebab-opts})
I get a H2 syntax error...
1. Unhandled org.h2.jdbc.JdbcSQLSyntaxErrorException
   Syntax error in SQL statement "INSERT INTO PUBLIC.ACCOUNT_HOLDERS (,[*] , , ,
   , ) VALUES (?, ?, ?, ?, ?, ?)"; expected "identifier"; SQL statement: INSERT
   INTO public.account_holders (, , , , , ) VALUES (?, ?, ?, ?, ?, ?)
An internet search seems to suggest that at least one of the column names is incorrect


user> next.jdbc/unqualified-snake-kebab-opts
{:qualifier-fn #'camel-snake-kebab.core/->kebab-case,
 :label-fn #'camel-snake-kebab.core/->kebab-case,
 :builder-fn #'next.jdbc.result-set/as-unqualified-kebab-maps,
 :column-fn #'camel-snake-kebab.core/->snake_case,
 :table-fn #'camel-snake-kebab.core/->snake_case}


i think you are passing a {:column-fn {:column-fn ...}} map. just use next.jdbc/unqualified-snake-kebab-opts as the options


@dpsutton Ah yes, blindingly obvious now you show me... it works. Thank you.

(jdbc-sql/insert! connection table record-data jdbc/unqualified-snake-kebab-opts)


And if you work with a datasource as your primary DB "thing", you can use jdbc/with-options to annotate the datasource with those snake-kebab-opts and then you have a (wrapped) datasource that you can execute/insert/update/etc and the options get automatically applied.


Hmm, I'll need to think what that means, but sounds useful. I've been using with-open with get-connection and with-transaction so will be good to read up on the unwrapping caveats in the docs. Will be adding connection pooling next and then seeing how much change is needed to get everything to work with postgresql. Lots of next.jdbc docs still to read. Thank you.


My recommendation is to create a pooled datasource (with HikariCP or c3p0) and just use that everywhere and only use get-connection if it is critical that a single connection is reused across multiple requests (unlikely, in my experience) and only use with-transaction where you absolutely need a transaction (also fairly rare, IME). That way you only have to worry about the unwrapping inside TX blocks.


But read the caveats in the docs about with-options and when things get unwrapped, e.g., get-connection and with-transaction


what do you think about adding the note about this in the Getting Started doc to the with-options docs? I was just about to ask this very question and I happened to see that you’ve already answered it 😄


@U3L6TFEJF It's explained in the Getting Started doc already: > Note: Because get-datasource and get-connection return plain JDBC objects (`javax.sql.DataSource` and java.sql.Connection respectively), next.jdbc/with-options cannot flow options across those calls, so if you are explicitly managing connections or transactions as above, you would need to have local bindings for the wrapped versions:


I guess I can add a note after the first mention to go read that section below...


@seancorfield yes, I’ve seen the note, what I mean is adding that “note” part to the with-options docstring :thumbsup:


the note explained it perfectly, I just couldn’t find it 😄


Ah, OK. I added this note to Getting Started to link the two sets of examples


I'll take a look at the docstring and see what I do. I do sort of assume folks read the whole the Getting Started guide before they, you know, get started 🙂


haha, that is certainly a fair assumption, just making a suggestion on behalf of all us speedreaders out there 😁 :thumbsup:


sweet, thank you! 🙂