Home > database >  How to define a user defined data type in clojure?
How to define a user defined data type in clojure?

Time:08-12

I want to use a user defined regex pattern for defining dates in edn file, for validation with malli. How do i define this pattern in core.clojure, so that I can use it in the edn file.

This is how my edn file was before.

(def reading-schema
  [:map
   [:readingDate :re #"\d{4}-\d{2}-\d{2}"]
   [:readingType string?]
   [:readingPrecision string?]
   [:readingEstimate string?]])

(def readingDetails-schema
  [:map
   [:readingCode string?]
   [:readingNumber string?]
   [:readingCheck string?]
   [:readings [:vector reading-schema]]])

But I am not able to load this to core.clj. How to resolve this? One way is to define in clojure. But I'm not aware of how to do it.

Let's say this is how I define my /edn file for all the schemas to be at one place.

  {
   :reading-schema [:map
                     [:readingDate :re #"\d{4}-\d{2}-\d{2}"]
                     [:readingType string?]
                     [:readingPrecision string?]
                     [:readingEstimate string?]]
    
    :readingDetails-schema [:map
                            [:readingCode string?]
                            [:readingNumber string?]
                            [:readingCheck string?]
                            [:readings [:vector reading-schema]]]
}

In core.clj, I'm calling it using aero library which is used by malli to call any edn file.


Edit: This is the error I'm facing:

Execution error at aero.core/read-pr-into-tagged-literal (core.cljc:180).
No dispatch macro for: "

CodePudding user response:

EDN does not support all reader macros (or "features") (see the built-in tagged elements) the clojure reader supports. But you can easily add your own readers (see :readers of opts):

user=> (doc clojure.edn/read)
-------------------------
clojure.edn/read
([] [stream] [opts stream])
  Reads the next object from stream, which must be an instance of
  java.io.PushbackReader or some derivee.  stream defaults to the
  current value of *in*.

  Reads data in the edn format (subset of Clojure data):
  http://edn-format.org

  opts is a map that can include the following keys:
  :eof - value to return on end-of-file. When not supplied, eof throws an exception.
  :readers  - a map of tag symbols to data-reader functions to be considered before default-data-readers.
              When not supplied, only the default-data-readers will be used.
  :default - A function of two args, that will, if present and no reader is found for a tag,
             be called with the tag and the value.

E.g.: add a reader for re, which then can be used to place before strings as #re in your EDN file.

(require '[clojure.edn :as edn])

(let [re (edn/read-string
           {:readers {'re re-pattern}} ; XXX
           (slurp "schema.edn"))]
  (assert (re-matches re "2022-01-01")))

Using this schema.edn

#re "\\d{4}-\\d{2}-\\d{2}"

(Watch out for the \ in the original regexp - in a string you need to escape them)

  • Related