David Williams
David Williams

Reputation: 8654

Clojure: How to Hook into Defrecord Constructor

The title of this question may over specify the implementation, but the idea is simple, I want to create and a record, or something similar, it could be a map a type declared by deftype, etc... I want to create the object with a string id and an int age, but I want to convert the id to a UUID and the age to an int if it is not already. How do I do this idiomatically?

So far I have something like this:

(let [item (my.model/map->Item {
    :id (UUID/fromString "62c36092-82a1-3a00-93d1-46196ee77204") 
    :age (int 6)})]) 

But I dont want to do both of those operations every time I create an item, I want that logic in 1 place. I could make an auxiliary function to do this, but is there built in support for this in deftype or defrecord?

Upvotes: 1

Views: 711

Answers (1)

noisesmith
noisesmith

Reputation: 20194

It's easiest to use a function that takes your input map and constructs your Item from that.

(defn make-item
  [{:keys [id age] :as input}]
  {:pre [(string? id)
         (number? age)]}
  (-> input
      (update-in [:id] #(UUID/fromString %))
      (update-in [:age] int)
      my.model/map->Item))

This will scale nicely as you need more keys or stricter constraints, and adapts to other record types.

Upvotes: 4

Related Questions