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 repoI believe :and propagates parsed values through its children.
spec2 has a schema that doesn't, perhaps that idea is applicable here https://github.com/clojure/spec-alpha2/blob/4cbfa677c4cd66339f18e1c122222c05c69e0d8e/src/main/clojure/clojure/alpha/spec.clj#L777
nice find
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
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
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])absolutely
I've been working to make the malli.generator for :and order-agnostic for about a year 🙂