Fork me on GitHub
#malli
<
2022-10-19
>
Joel03:10:14

Using the subschemas example, I wanted to pull out some custom data from the schema structure with the associated path. From something like this… [:street {:optional true :custom-field :value} string?] I want to make grab the path and that :value I put in that the properties. However, I see that using mu/subschemas does not return the properties. I guess I need to write my own walker? I find that puzzling since I think malli would need that :optional true info.

ikitommi04:10:09

could you paste a minimal repro here?

Joel13:10:27

(def Schema
  (m/schema
   [:map
    [:purchases {:optional true } [:set string?]]]))
 (mu/subschemas Schema)
When :purchases is walked, it doesn’t list the {:optional…}

ikitommi14:10:02

It’s because the properties are on the map-entry, not the child itself.

ikitommi14:10:34

there is mu/find that works like clojure.core/find, e.g. returns the [key properties value] entry.

ikitommi14:10:42

so, you can:

(def Schema
  (m/schema
   [:map
    [:purchases {:optional true} [:set string?]]]))

(defn get-in-props [schema path]
  (if-let [?entry (mu/find (mu/get-in schema (butlast path)) (last path))]
    (when (vector? ?entry) (second ?entry))))

(for [sub (mu/subschemas Schema)]
  (assoc sub :entry-props (get-in-props Schema (:path sub))))
;({:path [], :in [], :schema [:map [:purchases {:optional true} [:set string?]]], :entry-props nil}
; {:path [:purchases], :in [:purchases], :schema [:set string?], :entry-props {:optional true}}
; {:path [:purchases :malli.core/in], :in [:purchases :malli.core/in], :schema string?, :entry-props nil})

ikitommi14:10:45

hope that helps.

Joel14:10:57

looks like it will, ill give it a go.

Joel14:10:04

i don’t understand what :malli.core/in is “about”, but this gets me what i need - thanks!

ikitommi14:10:09

it's basically a pointer into to a homogeneous seq, "values in any position".

timothypratley06:10:09

Hi 👋 I'm trying to understand 2 things about catn:

'[:catn
     [m [:schema [:ref "m"]]]
     [s [:schema [:ref "s"]]]
     [_ [:orn [v [:schema [:ref "v"]]] [k [:schema [:ref "k"]]]]]]
1. It seems to produce the same output whether I use :orn or :altn -- is there a reason to prefer one over the other? 2. The result it produces is {m {:a 1}, s #{:a}, _ [k :k]} is there any way I can produce {m {:a 1}, s #{:a}, k :k} instead? Where the catn takes the name from the choice operator (`:orn`)? Below is the full schema but you can ignore most of it, it's just the choice between vector and keyword at the end that I'm focusing on:
'[:schema
  {:registry {"start" [:and vector?
                       [:catn
                        [m [:schema [:ref "m"]]]
                        [s [:schema [:ref "s"]]]
                        [_ [:orn [v [:schema [:ref "v"]]] [k [:schema [:ref "k"]]]]]]],
              "m"     map?,
              "s"     set?,
              "v"     [:and vector?
                       [:catn [a [:schema any?]] [b [:schema any?]] [c [:schema any?]]]],
              "k"     keyword?}}
  "start"]
And an example input:
'{m {:a 1}
  s #{:a}
  k :k}

👋 1
timothypratley20:10:17

One thing I discovered is that I can move the name binding "inside" cat using single argument orn instead of using catn:

[:cat
     [:orn [m [:schema [:ref "m"]]]]
     [:orn [s [:schema [:ref "s"]]]]
     [:altn [v [:schema [:ref "v"]]] [k [:schema [:ref "k"]]]]]
=> [[m {:a 1}] [s #{:a}] [k :k]] Which is interesting.

timothypratley23:10:07

Why does using a schema ref catn behave differently from an embedded catn:

(ma/parse
  '[:schema {:registry {"start" [:and vector? [:catn
                                               [a [:schema any?]]
                                               [b [:schema [:ref "b"]]]]],
                        "b" [:catn [c [:schema any?]] [d [:schema any?]]]}}
    "start"],
  '[1 (2 3)])

(ma/parse
  '[:schema {:registry {"start" [:and vector? [:catn
                                               [a [:schema any?]]
                                               [b [:catn [c [:schema any?]] [d [:schema any?]]]]]]}}
    "start"],
  '[1 2 3])
^^ The first (using a schema ref) matches a list inside a vector [1 (2 3)], whereas the second (embedded) matches a flat vector [1 2 3] -- I'm wondering if there is a way to use a ref to match a flat vector instead of a list.