malli
malli copied to clipboard
Merging :map and :multi
Coming from Clojure Spec, I would expect merging a :map
with a :multi
to work intuitively. Instead, I hit the merge-default
behavior in malli.util/merge
, which drops the first schema in favor of the second one. Naively, it seems like :multi could be handled more elegantly. Take the following scenario.
;; Malli Schema
(def Base [:map [:a string?]])
(def Full [:merge Base [:multi {:dispatch :type}
[:type1 [:map [:type1-k string?]]]]])
;; Same Schema, written in Spec
(s/def ::a string?)
(s/def ::base (s/keys :req-un [::a]))
(defmulti base-spec :type)
(s/def ::type1-k string?)
(defmethod base-spec :type1 [_] (s/keys :req-un [::type1-k]))
(s/def ::full
(s/merge ::base (s/multi-spec base-spec :type)))
If I m/explain
a value missing the :a
key, Malli will return true. I expected an explain that tells me I am missing a key.
(m/explain Full {:type :type1
:type1-k ""})
=> nil
Here is Spec's output.
(s/explain-data ::full {:type :type1
:type1-k ""})
=>
#:clojure.spec.alpha{:problems ({:path [],
:pred (clojure.core/fn [%] (clojure.core/contains? % :a)),
:val {:type :type1, :type1-k ""},
:via [:example/full
:example/base],
:in []}),
:spec :example/full,
:value {:type :type1, :type1-k ""}}
For our use cases, merging a :map with a :multi is a very common scenario. Is there interest in supporting this natively?
This is asked a lot. Just merge with all branches of do we need to derive effective types for schemas first (#264)?
Hi @kennyjwilli - did you solve this issue non-natively with Malli for the time being? If so, is it possible to share with the above as an example please? Thank you!
Yes @oryband, though I'm not fully satisfied with the solution, it does work for our use case -- just data validation. At each :merge
, I am able to loop through the children, validating if the data passes the child schema.