Fork me on GitHub
#malli
<
2021-03-22
>
robert-stuttaford07:03:21

haha just my luck, a week after i get started, the docs improve 😆 it looks great!

robert-stuttaford07:03:33

btw @ikitommi i ended up chunking the results of sets of 100 item m/provide into an atom and then m/union ing them together afterward. i ended up with a fair bit of [:or [:or [:or ....]]] but that was easy to remedy with a postwalk 🙂

ikitommi07:03:22

@robert-stuttaford good to hear. the right solution is to add few new Protocols (e.g. Inferrer and Provider) and attach the latter to the reified IntoSchemas: each instance know how to construct itself given a value and options. Internally using type/class-based lookup tables, it should be 2-4 orders of magnitude faster, and pluggable. Have an pre-initial draft somewhere 🙂

robert-stuttaford07:03:41

that sounds sane!

Panel10:03:39

(malli/encode
  [:or [:map
           [:password string?]
           [:password2 string?]]
     [:fn {:error/message "passwords don't match"}
      '(fn [{:keys [password password2]}]
         (= password password2))]]
  {:password "ok"}
  (mt/key-transformer {:encode  name}))
=> {:password "ok"}
(malli/encode
  [:and [:map
           [:password string?]
           [:password2 string?]]
     [:fn {:error/message "passwords don't match"}
      '(fn [{:keys [password password2]}]
         (= password password2))]]
  {:password "ok"}
  (mt/key-transformer {:encode  name}))
=> {"password" "ok"} Why doesn't encode work on the first one but does on the second, related to using :or instead of :and I guess.

ikitommi10:03:24

I believe neither of the examples doesn’t do anything, they are just just no-op.

nilern10:03:04

encode does not validate and those inputs are invalid, so nasal demons

ikitommi10:03:24

actually:

(-transformer [this transformer method options]
            (let [this-transformer (-value-transformer transformer this method options)]
              (if (seq children)
                (let [transformers (mapv #(or (-transformer % transformer method options) identity) children)
                      validators (mapv -validator children)]
                  (-intercepting this-transformer
                                 (if (= :decode method)
                                   (fn [x]
                                     (reduce-kv
                                       (fn [x i transformer]
                                         (let [x* (transformer x)]
                                           (if ((nth validators i) x*) (reduced x*) x)))
                                       x transformers))
                                   (fn [x]
                                     (reduce-kv
                                       (fn [x i validator] (if (validator x) (reduced ((nth transformers i) x)) x))
                                       x validators)))))
                (-intercepting this-transformer))))

nilern10:03:25

Although in terms of the implementation I think both of those should be no-ops

ikitommi10:03:47

it does validate and the first one fails -> doesn’t transform

nilern10:03:01

Ah yes so :or and seqex schemas validate when encoding because they have to pick a branch but nothing else (e.g. :and does) But that is implementation detail

nilern10:03:53

The recommended flow is first validate, then encode if ok, else explain Ceterum censeo, maybe some day we will have a thing that does all of that in one pass like Plumatic coerce

Panel10:03:23

Thanks for the explanations !

nilern10:03:24

This is my pet peeve and now I finally added an issue https://github.com/metosin/malli/issues/404 But it is a big decision and feature

robert-stuttaford14:03:25

is it possible for malli to report all errors instead of stopping on the first one?

nilern14:03:21

explain(er) should report all the errors. What are you seeing / not seeing?

robert-stuttaford14:03:54

ah, apologies. i'm using explain -> with-spell-checking -> humanize

robert-stuttaford14:03:20

seems humanize is dropping it

ikitommi14:03:29

really? should not.

robert-stuttaford14:03:19

lemme make reaaaal sure first, don't want to waste your time 😅

robert-stuttaford14:03:51

ok, it's not humanize. in the explain, the last error that i get is a :malli.core/input-remaining . when i fix that issue, then i get a new previously unreported error further down (happens to be the same issue: a kv-pair that should be one map level up)

robert-stuttaford14:03:06

so, is there some way have the whole sequence reported on at once?

robert-stuttaford14:03:41

basically, i'd like to use malli specs to provide a structural EDN linter in a web-based cms code editor. but for this one thing, it's working, beautifully

robert-stuttaford14:03:57

i am getting other errors from other collections, but the same issue manifests, in that i only get one error per such collection. i guess the question i'm asking is, how do i make :sequential and/or :+ check all elements

ikitommi14:03:09

Oh, the partial seqexp, no reporting / transformation on partially matched sequences atm. https://github.com/metosin/malli/issues/387

robert-stuttaford14:03:34

ok so this is because i'm using :+ rather than :sequential?

ikitommi14:03:40

not sure, could you give an example with actual and expected result?

robert-stuttaford14:03:24

ok, i switched to sequential, and this is the reason - thank you!

nilern14:03:37

You should use e.g. :sequential instead of :*/`:+` if you can

robert-stuttaford14:03:46

i can live without ensuring the sequence has at least one item

nilern14:03:04

[:sequential {:min 1} :int]

🎉 6
😅 3
robert-stuttaford14:03:43

ok rad i've got what i need. malli is lovely

robert-stuttaford14:03:24

now to use edamame's edn metadata stuff to wire up go-to-line links

nilern14:03:05

In general the seqex engine can't "resynchronize" after an erroneous element. We could have some optimizer that recognizes [:+ :int] and transforms it to [:sequential {:min 1} :int] but it would add complexity and unpredictability...

ikitommi14:03:22

did a malli + edamame poc some time ago, can’t recall was it any good, but pushed just as a gist: https://gist.github.com/ikitommi/0e5c4e48d8aeb7dd176128856ecdacb5

ikitommi14:03:52

something @borkdude was asking I think.

borkdude14:03:36

what I tried to do there is "complect" error message with locations directly

borkdude14:03:10

but I think you can just do explain and then look up the vals in the paths which have locations (or maybe they are already in the errors) and then postwalk the result to add the locations to the error messages

robert-stuttaford14:03:37

that second thing is what i'm doing

robert-stuttaford14:03:48

yeah @ikitommi your gist is the beautiful general version of the ugly hack i'm busy writing. going to start again with yours, thank you

nilern14:03:35

That code looks familiar :thinking_face:

borkdude14:03:19

@robert-stuttaford I think the second thing is probably the easiest?

ikitommi15:03:07

looking at the code, it has transduce, I never use that. I can’t recall the origins of the code, just from one of the zillion scratch files. could be @nilern s work too :thinking_face:

nilern15:03:37

Looking at the Metosin Slack history I did the unwrap and collect bits and remarked that the prewalk makes it O(n^2) but it only matters if there are large map keys or set members which hardly ever happens...

nilern15:03:28

Anyway it took a while to write so it would be cool if it found some use