Dasherize Korma Columns

A quick tip for the Korma SQL library for Clojure:

By default, Korma will return column names with underscores (e.g. :this_kind, unmodified from the database convention), while Clojurists are likely more comfortable with :this-kind of dash-separated keyword. (Some people call this “kebab-case” vs. “snake-case”). To wit:

(defentity locations
  (belongs-to user))

(select locations)
; => ({:user_id 1, :latitude 30.02, :longitude -116.992})

We can convince Korma to automatically translate these names using Korma’s own prepare and transform functions, which are given the chance to mutate attribute names and values on the way to / from the database, as Conan Cook points out in his Tasty Korma Recipes post. But it gets a bit cumbersome to inline this code in every entity definition.

Building on that idea, here’s single function you can drop in your code and invoke in your defentity forms to take care of the translation:

(defn- normalize-keys
  "Invoke in a `defentity` form to automatically translate between
  dash-separated keywords and underscore-separated DB column names."
  [ent]
  (let [map-keys (fn [f m] (reduce-kv #(assoc %1 (f %2) %3) {} m))
        underscore-kw (comp keyword #(clojure.string/replace % "-" "_") name)
        dasherize-kw  (comp keyword #(clojure.string/replace % "_" "-") name)]
    (-> ent
        (korma.core/prepare   (partial map-keys underscore-kw))
        (korma.core/transform (partial map-keys dasherize-kw)))))

If we now add that to our entity definition, the translation is cleanly handled:

(defentity locations
  (belongs-to user)
  (normalize-keys))

(select locations)
; => ({:user-id 1, :latitude 30.02, :longitude -116.992})