malli

cheewah 2024-12-09T23:26:48.489469Z

Hi, may I know if there is a way to decode a referenced [:enum ...] (i.e. via :ref) to its default value? I use :ref for both [:enum ...] and [:map ...] , hence am not sure how to make the default-value-transformer support both cases. For example:

(def schema1 {:ns/MyMsg [:map {:closed true}
                         [:int32_val  :int]
                         [:nested_msg [:ref :ns/MyNestedMsg]] ; <--- ref [:map ...]
                         [:my_enum    [:ref :ns/MyEnum]]]     ; <--- ref [:enum ...]
             :ns/MyNestedMsg [:map {:closed true}
                             [:string_val :string]]
             :ns/MyEnum [:enum
                         :ZERO :ONE :TWO]})

(def registry1 {:registry (malli.registry/composite-registry
                           malli.core/default-registry
                           schema1)})

(def vt1 (malli.transform/default-value-transformer
          {:defaults {:int (constantly 0)
                      :string (constantly "")
                      :ref (constantly {})}})) ; <--- works for ref [:map ...] only

(malli.core/decode [:ref :ns/MyMsg]
                   {}
                   registry1
                   vt1)
outputs:
{:int32_val 0,
 :nested_msg {:string_val ""},
 :my_enum {}}
but ideally :my_enum should be :ZERO
{:int32_val 0,
 :nested_msg {:string_val ""},
 :my_enum :ZERO}

opqdonut 2024-12-10T07:16:39.590999Z

hmm... interesting!

opqdonut 2024-12-10T07:17:01.758669Z

arguably default-value-transformer should deref the schemas to see through the :ref, to the default of the underlying schema

👍 1
opqdonut 2024-12-10T07:26:05.423629Z

here's a workaround:

opqdonut 2024-12-10T07:26:08.832099Z

(def schema-with-defaults {:ns/MyMsg [:map {:closed true}
                                      [:int32_val  :int]
                                      [:nested_msg [:ref :ns/MyNestedMsg]]
                                      [:my_enum    [:ref :ns/MyEnum]]]
                           :ns/MyNestedMsg [:map {:closed true :default {:string_val "DEFAULT"}}
                                            [:string_val :string]]
                           :ns/MyEnum [:enum {:default :ZERO}
                                       :ZERO :ONE :TWO]})

(def registry2 {:registry (malli.registry/composite-registry malli.core/default-registry
                                                             schema-with-defaults)})

(def vt3 (malli.transform/default-value-transformer {:defaults {:int (constantly 0)
                                                                :ref (fn [schema] (-> schema
                                                                                      malli.core/deref
                                                                                      malli.core/properties
                                                                                      :defaults))}}))

(malli.core/decode [:ref :ns/MyMsg] {} registry2 vt3)
;; ==> {:int32_val 0, :nested_msg {:string_val "DEFAULT"}, :my_enum :ZERO}

👍 1
opqdonut 2024-12-10T07:26:40.405789Z

it needs the :reffed schemas to have explicit :default keys

opqdonut 2024-12-10T07:33:23.703899Z

interestingly, this is only a problem inside maps:

(malli.core/decode [:vector [:ref "bing"]]
                   [nil]
                   {:registry (malli.registry/composite-registry malli.core/default-registry
                                                                 {"bing" :int})}
                   (malli.transform/default-value-transformer {:defaults {:int (constantly 7)}}))
;; ==> [7]

opqdonut 2024-12-10T07:34:24.413949Z

I'll file a bug. I'm not sure what the right solution would be

👍 1
cheewah 2024-12-10T07:39:37.422909Z

thanks @joel.kaasinen, appreciate with the filing of bug and the workaround is also very useful for me to experiment with different possibilities. also, jfyi generate function seems to work well with :ref already. hence maybe another possibility is to make generate support generating with default value?

(def schema1 {:ns/MyMsg [:map {:closed true}
                         [:int32_val  :int]
                         [:nested_msg [:ref :ns/MyNestedMsg]] ; <--- ref [:map ...]
                         [:my_enum    [:ref :ns/MyEnum]]]     ; <--- ref [:enum ...]
             :ns/MyNestedMsg [:map {:closed true}
                             [:string_val :string]]
             :ns/MyEnum [:enum
                         :ZERO :ONE :TWO]})

(def registry1 {:registry (malli.registry/composite-registry
                           malli.core/default-registry
                           schema1)})

(malli.generator/generate [:ref :ns/MyMsg] registry1)
; {:int32_val 157129, :nested_msg {:string_val "HLFfHa679Q"}, :my_enum :TWO}

opqdonut 2024-12-10T07:43:25.383599Z

https://github.com/metosin/malli/issues/1145

👍 1
opqdonut 2024-12-10T08:12:01.462489Z

I think I might have a fix...

opqdonut 2024-12-10T08:30:25.109049Z

https://github.com/metosin/malli/issues/1145

👍 1