Polymorphic Schemas in Clojure

498 views Asked by At

I want to create polymorphic schemas/types, and I'm curious of best practices. The following 2 examples allow me to create a Frequency schema which can repeat an event monthly by day of month, or monthly by day of week (eg, every 15th, or every first monday, respectively).

The first one uses the experimental abstract map to accomplish this, and its syntax of it is awkward (IMO). Plus being in the experimental package concerns me a bit.

The second one uses s/conditional, and this suffers from not being able to easily coerce the value of type from a string to keyword, which is useful when dealing with a REST API, or JSON. (whereas s/eq is great for this).

In the general case, is one of these, or some third option, the best practice for conveying: Type A is one of Types #{B C D ...}?

Two options:

;;OPTION 1
​
(s/defschema Frequency (field (abstract-map/abstract-map-schema
                               :type {})
                              {}))
(abstract-map/extend-schema MonthlyByDOM Frequency
                            [:monthly-by-dom]
                            {:days #{MonthDay}})
(abstract-map/extend-schema MonthlyByDOW Frequency
                            [:monthly-by-dow]
                            {:days  #{WeekDay}
                             :weeks #{(s/enum 1 2 3 4 5)}})

;;OPTION 2
​
(s/defschema MonthlyByDOM "monthly by day of month, eg every 13th and 21st day" {:type (s/eq :monthly-by-dom)
                                                                                 :days #{MonthDay}})
(s/defschema MonthlyByDOW "monthly by day of week, eg first, and third friday" {:type  (s/eq :monthly-by-dow)
                                                                                :days  #{WeekDay}
                                                                                :weeks #{(s/enum 1 2 3 4 5)}})
(s/defschema Frequency (field (s/conditional #(= (s/eq :monthly-by-dom) (do (prn %) (:type %))) MonthlyByDOM
                                             #(= :monthly-by-dow (:type %)) MonthlyByDOW)
                              {:default {:type :monthly-by-dom
                                         :days #{1 11 21}}}))

Similar questions that don't quite help:

0

There are 0 answers