Create a record based on the string class name

Viewed 88

I'm trying to create an event store where I have a table somewhat like this:

CREATE TABLE domain_events (
  id serial PRIMARY KEY,
  timestamp timestamptz,
  entity_id int,
  type text,
  data jsonb
);

And I have a namespace like

(ns my-domain.domain-events)

(defrecord PurchaseOrderCreated
  [id timestamp purchase-order-id created-by])

(defrecord PurchaseOrderCancelled
  [id timestamp purchase-order-id cancelled-by])

So type is a string name for the fully qualified class name, something like my_domain.domain_events.PurchaseOrderCreated, which comes from getting the type from a record e.g. (type (->PurchaseOrderCreated)). I should note that (type the-event) actually produces a string prefixed with class such as class my_domain.domain_events.PurchaseOrderCreaated so I am trimming this off before storing in the DB.

I'm trying to figure out how I can retrieve these event rows from the database and rehydrate them to domain events. I feel like I'm close but just haven't been able to get all the pieces.

I've tried to use new to construct a new record but I seem to have a hard time converting the string classname to a record.

(new (resolve (symbol "my_domain.domain_events.PurchaseOrderCreated")) prop1 prop2 ...)

Plus I'm not sure how easy it's going to be to use new since my array-of-properties is going to need to be in the correct order. It may be better to use the map->PurchaseOrderCreated but I'm still not sure how to dynamically resolve this constructor based on the string classname.

Can anybody advise on what the best approach would be here?

1 Answers

The following should work but I'm not show if there's a more idiomatic way for it:

((resolve (symbol "my_domain.domain_events"
                  (str "map->"
                       "PurchaseOrderCreated")))
 {:id 123})

symbol takes can take a ns: https://clojuredocs.org/clojure.core/symbol

Related