malli icon indicating copy to clipboard operation
malli copied to clipboard

Merging :map and :multi

Open kennyjwilli opened this issue 3 years ago • 3 comments

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?

kennyjwilli avatar Jul 29 '21 21:07 kennyjwilli

This is asked a lot. Just merge with all branches of do we need to derive effective types for schemas first (#264)?

ikitommi avatar Jul 30 '21 13:07 ikitommi

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!

oryband avatar Oct 04 '21 18:10 oryband

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.

kennyjwilli avatar Oct 04 '21 22:10 kennyjwilli