2

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: "
MouseNag
  • 303
  • 1
  • 9
  • "But I am not able to load this" - please add the error you get. Also do you _really_ want to have `def` in there? Do you actually want to load this file als _code_ and the user of your app should be apbel to provide this file? In that case, you could just tell user to create this file, put it on classpath, and you `require` it. – cfrick Aug 11 '22 at 08:50
  • Yes, I've added the error now. And I was xhecking with def because I wanted to check in repl. So I was defining scehmas on the go & checking. Now I want to store all the schemas in an edn file. – MouseNag Aug 11 '22 at 10:40

1 Answers1

3

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)

cfrick
  • 35,203
  • 6
  • 56
  • 68