malli 2025-01-28

Hi, I am trying to see if I can use parse on some pretty hairy schemas to help bring clarity at work. I'm hitting something interesting, where validation functions tied to schemas are passed the parsed value when using m/parse. 🧵

It seems like that is not the intended behavior, but here's what I am seeing locally: These print different things, but that's not a big problem:

(mc/validate [:and [:catn ["a" :int] ["b" :keyword]]
              [:fn (fn [x] (prn x) true)]]
             [3 :x])
;; prints: [3 :x]

(mc/parse [:and [:catn ["a" :int] ["b" :keyword]]
           [:fn (fn [x] (prn x) true)]]
          [3 :x])
;; prints: {"a" 3, "b" :x}
The problem I'm hitting is when we actually try to validate these things with the attached :fn schema:
(mc/validate [:and [:catn ["a" :int] ["b" :keyword]]
              [:fn vector?]]
             [3 :x])
;; prints: [3 :x]

(mc/parse [:and [:catn ["a" :int] ["b" :keyword]]
           [:fn vector?]]
          [3 :x])
;; => :malli.core/invalid
I sort of can work around it by checking for e.g. (if it's a map with these keys, then it passes validation). but that's not really ideal. I'll look for an issue in the repo

I believe :and propagates parsed values through its children.

needs a bit more thought, not sure why this case fails

(let [s [:and {:parse :non-flowing}
                        [:catn ["a" :int] ["b" :keyword]]
                        [:fn vector?]]]
                 (m/unparse s (m/parse s [3 :x])))

@escherize I've fixed the :and parser's reliability, please give it a shot. Also comes with a shiny new schema :andn https://github.com/metosin/malli/pull/1182

2

swapping the order of all children of :ands so the :fn validations come before the :catns actually works in my case (and this is a truly complex schema) https://github.com/metabase/metabase/blob/master/src/metabase/lib/schema/parameter.cljc#L200-L204 if you're curious. Also I can unparse it back if I do it this way.

Maybe if the :and parser sorts the children in the correct order that will fix it w/o needing to figure out how to unparse w/ :parser :non-flowing

[:and :catn :fn] is better for malli.generator and [:and :fn :catn] is better for m/parse...gah

➕ 1

Another idea is to only allow one transforming parser, and treat the rest as predicates. but you don't know which it is until you do the parsing, which means it's unclear how to unparse. both ideas need to distinguish between parsers that transform and those that don't somehow.

properties on :and seem to be a good way to communicate this.

wouldn't it be cool to never care about the order tho? Could it even work tho... probably not, consider:

(m/validate [:and
             [:catn ["a" :int] ["b" :keyword]]
             [:tuple :int :keyword]]
            [1 :a])

I've been working to make the malli.generator for :and order-agnostic for about a year 🙂

❤️ 1