Fork me on GitHub
#malli
<
2022-09-28
>
Martynas Maciulevičius09:09:13

What does this error mean? https://github.com/metosin/malli/blob/c0965e2b2b37ea1d81e6f4ece7c87f56fa90398a/test/malli/core_test.cljc#L1799 I get it when I try to have a malli schema to decode malli tuples. And well... it has to be recursive :thinking_face:

Martynas Maciulevičius09:09:40

I fixed the error by not using :ref in the definition like this:

::malli-tuple-schema [:cat
                      [:= :tuple]
                      [:* ::malli-schema]
                      #_[:* [:ref ::malli-schema]]]

ambrosebs13:09:01

I think it means that any regex operation cannot contain a recursive schema. checking for :ref is a crude way of checking for recursion.

ambrosebs13:09:39

I developed a more refined way to detect recursive specs in the generators namespace. perhaps using that here would be a nice enhancement.

Martynas Maciulevičius13:09:43

> cannot contain a recursive schema Well if I remove the :ref it will still reference the ::malli-schema but it will copy it. So the schema works the same way as it would work with :ref

ambrosebs13:09:48

Agreed. That's the part that I think could potentially be improved.

ambrosebs13:09:15

eg., the ;; A bit undesirable, but intentional: test a few lines down from the test you linked.

ambrosebs13:09:27

is ::malli-schema recursive?

Martynas Maciulevičius13:09:37

Everything there is recursive 😄

Martynas Maciulevičius13:09:51

::malli-schema [:or
                                [:ref ::malli-map-schema]
                                [:ref ::malli-set-schema]
                                [:ref ::malli-vector-schema]
                                [:ref ::malli-tuple-schema]
                                :keyword]

ambrosebs13:09:17

ah. I'm confused, you said you "fixed the error", what does that look like now?

Martynas Maciulevičius13:09:37

This looks like [:* ::malli-schema] and it works without the error

ambrosebs13:09:25

thanks. now I understand how crude this check is 🙂

ambrosebs13:09:25

I thought it was an overapproximation on checking for recursive specs. but it only guards against very specific recursive ones.

ambrosebs13:09:47

unless I'm missing something.

Martynas Maciulevičius13:09:26

This is a more basic example that passes the checker:

[:schema
 {:registry
  {::malli-field-options [:map
                          [:optional {:optional true} :boolean]
                          [:min {:optional true} :int]
                          [:registry {:optional true} ::malli-map-schema]],
   ::malli-map-schema [:cat
                       [:= :map]
                       [:* [:or
                            [:tuple :keyword [:ref ::malli-schema]]
                            [:tuple :keyword [:ref ::malli-field-options] [:ref ::malli-schema]]]]],
   ::malli-schema [:or
                   [:ref ::malli-map-schema]
                   :keyword]}}
 ::malli-schema]

ambrosebs13:09:35

ok, and that one has no references/`:ref` directly on regex ops. can you post the full one that yields the error and requires a change?

Martynas Maciulevičius13:09:23

I don't know. I can't find it

Martynas Maciulevičius13:09:36

I'll probably be editing it more. Maybe I can find it later. But when I got that bug I was unsure what to do. So it's a tough one.

ambrosebs13:09:10

np, just sounds like a good test case. I get the gist of it.

ikitommi07:10:53

the :ref can’t be used to expand/inline things into a sequential schema. you can use :refs, but need to wrap it into :schema - takes just one position in the sequence. This is an implementation decision, described in the ns. If there is a performant way not to do this, I’m all 👂s!

diego.videco20:09:11

Got a question about malli’s :re schemas. I’ve got this code for validating email addresses:

(def email-address-regex  #"(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])")
(def email-address? [:re {:error/message "Please provide a valid email address"} email-address-regex])

(me/humanize (m/explain email-address? ",bad-email")) ;; will say it's valid
(re-matches email-address-regex ",bad-email") ;; will not match anything
It seems like :re is using re-find because re-find does return true, but what can I do to make :re behave more like re-match ?

iarenaza09:09:51

Yeah, it seems it's using re-find for validation: https://github.com/metosin/malli/blob/0.8.9/src/malli/core.cljc#L1350-L1351 In that case, you need to use the "beginning of line/string" (`^`) and "end of line/string" (`$`) anchors in your regular expression, so that re-find must match your regular expression over the whole input value, not just a part of it:

user> (require '[malli.core :as m])
nil
user> (require '[malli.error :as me])
nil
user> (def email-address-regex  #"^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:\
(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$")
#'user/email-address-regex
user> (def email-address? [:re {:error/message "Please provide a valid email address"} email-address-regex])
#'user/email-address?
user> (me/humanize (m/explain email-address? ",bad-email")) ;; will say it's invalid
["Please provide a valid email address"]
user> (re-matches email-address-regex ",bad-email") ;; will not match anything
nil
user> (re-find email-address-regex ",bad-email") ;; will not match anything either
nil
user>