Schema Parsing
ikitommi opened this issue · 6 comments
Currently, m/explain
parses the values in align to the Schemas, producing :in
and :path
paths pointing paths in both values and schemas. This is a good base for generic parsing, e.g. Clojure Spec conform. We could reuse the m/-explain
to collect paths for valid & invalid errors. The resulting ~conformed data structure could be self-describing, so that no m/-unexplain
would be needed to turn the parsed data structure back into value, like spec has s/unform
. This could be achieved using special types/records to mark branching, instead of just maps and vectors (which can't be found from values without per-schema method).
From spec:
(s/def ::name-or-id (s/or :name string?
:id int?))
(s/conform ::name-or-id "abc")
;;=> [:name "abc"]
(s/conform ::name-or-id 100)
;;=> [:id 100]
Would be ~:
(m/parse [:or string? int?] "abd")
;; => #Branch{:path 0, :value "abc"}
(m/parse [:or string? int?] 100)
;; => #Branch{:path 1, :value 100}
And with named branches:
(m/parse [:orn [:string string?] [:int int?]] "abd")
;; => #Branch{:path :string, :value "abc"}
(m/parse [:orn [:string string?] [:int int?]] 100)
;; => #Branch{:path :int, :value 100}
As a bonus, we could present errors in the parse tree in-place.
See also #180.
I would also like to see something like s/conformer
in malli:
ported the conformer
example against the current api: validate + encode + validate + encode.
(def Schema1 [:string {:encode/conform #(mapv str (seq %))}])
(def Schema2 [:sequential {:encode/conform #(apply str %)} [:enum "0" "1"]])
(def conformer (mt/transformer {:name :conform}))
(as-> "1011" $
(do (println $ "=>" (m/validate Schema1 $)) $)
(m/encode Schema1 $ conformer)
(do (println (pr-str $) "=>" (m/validate Schema2 $)) $)
(m/encode Schema2 $ conformer)
(= "1011" $))
; 1011 => true
; ["1" "0" "1" "1"] => true
; => true
#312 has most of the required logic, but only for regex schemas so I haven't added any public API. Destructuring other schemas should be much more straightforward though.
Working on this in #317. Although maybe this should have a separate PR but I'll see how it goes.
And I put zero thought into the design, just trying to get something workable to demonstrate that #317 can also support this. So it is just the obvious cross between malli.core/explainer
and clojure.spec.alpha/conform
.
explain & parse can be merged later. This is in master. Thanks!!