Skip to content

Instantly share code, notes, and snippets.

@pithyless
Last active August 16, 2022 03:59
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pithyless/0be222e1b1b3bca0239a9ca07d1b34c2 to your computer and use it in GitHub Desktop.
Save pithyless/0be222e1b1b3bca0239a9ca07d1b34c2 to your computer and use it in GitHub Desktop.
malli-meander.clj
(ns demo
(:require
[malli.core :as m]
[malli.transform :as mt]
[meander.epsilon :as meander]))
;; NOTE: Also important to mention I used m/validate m/parse etc.,
;; but these should all be replaced with m/validator, m/parser etc.
;; in production code
(def source-shape
[:map
[:events [:sequential
[:map
[:id int?]
[:desc string?]
[:details-id int?]]]]
[:details [:sequential
[:map
[:id int?]
[:content string?]]]]])
(def destination-shape
[:sequential
[:map
[:id int?]
[:description string?]
[:details string?]]])
(defn custom-transform-logic
[data]
(-> data
(meander/search
{:events (meander/scan
{:id ?event-id
:desc ?description
:details-id ?details-id})
:details (meander/scan
{:id ?details-id
:content ?details})}
{:id ?event-id
:description ?description
:details ?details})
vec))
(def sample-data
{:events [{:id "1"
:desc "Blah"
:details-id "11"}
{:id "2"
:desc "Blah 2"
:details-id "12"}]
:details [{:id "11"
:content "Blargh"}
{:id "12"
:content "Blargh 2"}]})
;; Example broken input
(def sample-data2
{:events [{:id nil
:desc "Blah"
:details-id 11}]
:details [{:id "11"
:content "Blargh"}]})
(comment
(let [raw-data sample-data
;; First, normalize input (this is best-effort and does not throw errors).
;; This can take care of things like converting strings to integers, because
;; the serialization protocol could not represent integers, etc.
decoded (m/decode source-shape raw-data mt/string-transformer)
;; Second, validate that the normalized input matches our expectations.
;; NOTE: you can use m/validate instead of m/parse if schema has branching logic,
;; but you don't want to take advantage of the extra information at this point.
;; NOTE 2: you could use a different, more strict schema at this point.
parsed (m/parse source-shape decoded)
_ (when (identical? parsed ::m/invalid)
(throw (ex-info "Invalid Input" (m/explain source-shape decoded))))
;; At this point we've validated input and want to do transformation
transformed (custom-transform-logic parsed)
;; And would be good idea to validate transformation worked...
_ (when-not (m/validate destination-shape transformed)
(throw (ex-info "Invalid Transformation" (m/explain destination-shape transformed))))]
transformed)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment