Fork me on GitHub
#malli
<
2020-12-22
>
elarouss22:12:47

Hi, Is it possible to write a schema for this vector:

[{:type :work
  :value ""}
 {:type :personal
  :value ""}]
the vector should only contain those 2 items, where the type is kind of static, the value can change. i thought about using this schema:
[:vector [:map [:type keyword?] [:value string?]]]
but it’s not enough for my use case, because i want when i inspect the schema to know how many items i can have in the vector, and their types (the :type ) is this possible? Thank you for the great lib 🙏

alpox23:12:43

@U6AE62UCT I can think of two ways:

(def data-schema [:map
                   [:type [:enum :work :personal]]
                   [:value string?]])
for the maps and then
(def schema [:vector {:min 2 :max 2} data-schema])
or maybe
(def schema [:tuple data-schema data-schema])
for putting together the schema for the vector

elarouss07:12:01

I was thinking about something like

[:vector
     [:map [:type :work] [:value string?]]
     [:map [:type :personal] [:value string?]]]
but it didn’t work Thank you @U6JS7B99S i’ll probably go with your first suggestion

ikitommi08:12:47

if the :type defines the shape of the data, you can try :multi:

(require '[malli.generator :as mg])

(mg/sample
  [:vector {:min 2, :max 2}
   [:multi {:dispatch :type}
    [:work [:map [:type [:= :work]] [:value string?]]]
    [:personal [:map [:type [:= :personal]] [:value string?]]]]])

(mg/sample
  [:tuple {:registry
           {::element
            [:multi {:dispatch :type}
             [:work [:map [:type [:= :work]] [:value string?]]]
             [:personal [:map [:type [:= :personal]] [:value string?]]]]}}
   ::element ::element])

ikitommi08:12:10

both emit results like:

([{:type :personal, :value ""} {:type :work, :value ""}]
 [{:type :work, :value "l"} {:type :personal, :value ""}]
 [{:type :personal, :value "z1"} {:type :personal, :value ""}]
 [{:type :personal, :value "ZG"} {:type :personal, :value "N"}]
 [{:type :personal, :value "qQ6"} {:type :work, :value "A8h"}]
 [{:type :personal, :value "2588"} {:type :personal, :value "Djv12"}]
 [{:type :work, :value ""} {:type :personal, :value "c"}]
 [{:type :work, :value "U2uHMI"} {:type :personal, :value "376ihr"}]
 [{:type :personal, :value "n6Ct4d"} {:type :personal, :value "V09xL8"}]
 [{:type :work, :value "9"} {:type :personal, :value ""}])

ikitommi08:12:55

if the first map is always work and second personal, :tuple for the win:

[:tuple
 [:map [:type :work] [:value string?]]
 [:map [:type :personal] [:value string?]]]

elarouss08:12:52

Thank you, the :multi works for my use case 🙏

ikitommi08:12:47

if the :type defines the shape of the data, you can try :multi:

(require '[malli.generator :as mg])

(mg/sample
  [:vector {:min 2, :max 2}
   [:multi {:dispatch :type}
    [:work [:map [:type [:= :work]] [:value string?]]]
    [:personal [:map [:type [:= :personal]] [:value string?]]]]])

(mg/sample
  [:tuple {:registry
           {::element
            [:multi {:dispatch :type}
             [:work [:map [:type [:= :work]] [:value string?]]]
             [:personal [:map [:type [:= :personal]] [:value string?]]]]}}
   ::element ::element])