malli

https://github.com/metosin/malli :malli:
Yevgeni Tsodikov 2021-03-21T11:02:10.126300Z

Hey, This might be a silly question. Is it possible to validate a map while ignoring optional fields if they are invalid? for example it would return false here:

(m/validate [:map 
             [:a string?]
             [:b {:optional true} int?]]
            {:a "Hey" :b "Nope"})
=> false
But there would be a way to conform a map with invalid optional fields and “sanitize” the map
; This made-up function would return {:a "Hey"}
(m/conform [:map 
            [:a string?] 
            [:b {:optional true} int?]]
           {:a "Hey" :b "Nope"})

ikitommi 2021-03-21T11:15:27.126600Z

Do you mean the first should return true?

Hankstenberg 2021-03-21T12:00:10.126800Z

Hm, shouldn't a validation with an open map that just containts the schema for :a do the trick? Or let b be any? Under what circumstances should b be an int?

Hankstenberg 2021-03-21T13:11:46.127900Z

@ikitommi That's something I'd like to be able to do too. Is there an idiomatic way to do that?

Yevgeni Tsodikov 2021-03-21T13:15:39.128100Z

> Do you mean the first should return `true`? Yes 🙂 > recursively remove all values in `:errors` `:in` path. the invalid paths are part of the explain result: The :optional data is missing from the :schema field, how can I know which field is safe to remove and which field makes the map actually invalid?

Yevgeni Tsodikov 2021-03-21T13:19:55.128500Z

My scenario is an API with some optional fields. If the client doesn’t send then -> no worries. If the client sent some invalid optional fields, in some cases I’d like to pass the request and not fail it. (Such cases may be that the client is a mobile device with a crappy sdk, which might report invalid data for optional fields)

Yevgeni Tsodikov 2021-03-21T13:34:49.128700Z

Also - > Do you mean the first should return `true`? Not without some hints or options.

; This is correct
(m/validate [:map 
             [:a string?]
             [:b {:optional true} int?]]
            {:a "Hey" :b "Nope"})
=> false

; Additional options
(m/validate [:map 
             [:a string?]
             [:b {:optional true} int?]]
            {:a "Hey" :b "Nope"}
            {:fail-on-optional? false)
=> true

ikitommi 2021-03-21T14:06:59.129100Z

ikitommi 2021-03-21T14:07:26.129600Z

ping @evg.tso

ikitommi 2021-03-21T14:12:36.130300Z

as the slack history rolls out fast, pasted the example into https://github.com/metosin/malli/blob/master/docs/tips.md#allowing-invalid-values-on-optional-keys

Yevgeni Tsodikov 2021-03-21T14:22:35.130900Z

That’s great, thanks @ikitommi!

Yevgeni Tsodikov 2021-03-21T14:35:11.131100Z

Is there a way to conform/remove the invalid optional fields?

ikitommi 2021-03-21T14:51:25.131300Z

yes. Many ways to do that : 1) attach a custom transformer to the new :any fields to strip those away 2) in case of error, call m/explain and remove all values from paths that have error

ikitommi 2021-03-21T14:51:56.131500Z

don't have time to write an example, but definitely doable 😉

Yevgeni Tsodikov 2021-03-21T15:37:07.131700Z

The allow-invalid-optional-values function is missing the (m/options s) arg of mu/transform-entries

respatialized 2021-03-21T16:15:17.131900Z

hi! I've been really impressed with malli so far. really appreciate all the work you've put into it. I'm trying to generate sample values from a schema, and I'm encountering a case where :orn fails and :altn succeeds:

(mg/generate [:altn [:bool boolean?] [:num int?]] {:seed 20})
=> [true]
(mg/generate [:orn [:bool boolean?] [:num int?]] {:seed 20})
=> Execution error (ExceptionInfo) at malli.impl.util/-fail! (util.cljc:16).
:malli.generator/no-generator {:schema [:orn [:bool boolean?] [:num int?]], :options {:seed 20}}
Is this expected at this stage? Is there additional implementation for :orn generators that still needs to be done, or is this a bug?

respatialized 2021-03-21T16:17:32.132Z

simple :or also succeeds on this case:

(mg/generate [:or boolean?  int?] {:seed 20})
=> true

Yevgeni Tsodikov 2021-03-21T16:18:02.132100Z

What’s your opinion on something like:

(defn allow-invalid-optional-values [schema]
  (m/walk
    schema
    (m/schema-walker
      (fn [s]
        (cond-> s
                (m/entries s)
                (mu/transform-entries
                  (partial map (fn [[k {:keys [optional] :as p} s]]
                                 (if optional
                                   [k
                                    (assoc p :original-spec s
                                             :decode/remove-invalid-fields {:compile (fn [schema _]
                                                                                       (fn [x]
                                                                                         (if-let [original-spec (:original-spec (m/properties schema))]
                                                                                           (when (m/validate original-spec x)
                                                                                             x)
                                                                                           x)))})
                                    :any]
                                   [k p s])))
                  (m/options s)))))))

(-> [:map
     [:a string?]
     [:b {:optional true} int?]]
    allow-invalid-optional-values
    (m/decode
      {:a "Hey" :b "Nope"}
      (mt/transformer {:name :remove-invalid-fields})))
=> {:a "Hey", :b nil}
I don’t like having multiple transformers, though. How can I unify them? Similarly to what malli offers with mt/strip-extra-keys-transformer ?

ikitommi 2021-03-21T16:49:19.132700Z

@afoltzm 🙇 , see https://github.com/metosin/malli/pull/400

😮 1
ikitommi 2021-03-21T16:54:33.133100Z

merged in master

🎉 2
respatialized 2021-03-21T17:04:57.134Z

wow, that was fast! thanks!

borkdude 2021-03-21T17:05:13.134400Z

it's weekend, the time where magic OSS happens

🙌 1
ikitommi 2021-03-21T18:09:51.135400Z

pushed out [metosin/malli "0.3.1"], finally with a working cljdoc - https://cljdoc.org/d/metosin/malli/0.3.1/doc/changelog.

😍 8