malli

niwinz 2024-08-13T15:53:04.129419Z

Hello, I have a question about how key-transformer works. When using key-transformer to decode a data structure, if that data structure has maps inside vectors. Should the maps inside vectors be transformed accordingly? I have found that the transformation stops when the vector is found, however I would expect it to transform all objects of type :map recursively. Am I doing something wrong?

niwinz 2024-08-13T15:53:36.666899Z

Example code:

niwinz 2024-08-13T15:54:20.865459Z

look that on the roundtrip test output/result, the map inside vector is not transformed.

niwinz 2024-08-13T16:03:23.781559Z

Looks like the encoding is doing correctly, making all keys camel case, but the decoding skips the fills vector

ikitommi 2024-08-13T16:16:42.797449Z

Could you paste code as text?

niwinz 2024-08-13T16:22:56.041149Z

(def schema:fill
  [:map
   [:color :string]
   [:some-id :int]])

(def schema:test-1
  [:and
   [:multi {:dispatch :type
            :decode/string {:enter #(update % :type keyword)}}
    [:group
     [:map
      [:type [:= :group]]
      [:font-family :string]
      [:font-size :int]
      [:fills [:vector schema:fill]]]]]

   [:fn some?]])

(def key-transformer
  (sm/key-transformer {:encode json/write-camel-key
                       :decode json/read-kebab-key
                       :types #{:map :map-of :multi}}))

(def test-data
  {:font-family "foobar"
   :font-size 10
   :type :group
   :fills [{:color "#aaaaaa" :some-id 1}]})

(def encoder
  (sm/encoder schema:test-1 key-transformer))

(def decoder
  (sm/decoder schema:test-1 key-transformer))

(defn run-roundtrip-test
  []
  (-> test-data
      (encoder)
      (json/encode)
      (json/decode)
      (decoder)))

;; The output is:
(comment
  {:font-family "foobar",
   :font-size 10,
   :type "group",
   :fills [{"color" "#aaaaaa", "someId" 1}]})

niwinz 2024-08-13T16:24:01.218669Z

(defn read-kebab-key
  [k]
  (-> k str/kebab keyword))

(defn write-camel-key
  [k]
  (if (or (keyword? k) (symbol? k))
    (str/camel k)
    (str k)))
The auxiliar functions based on cuerdas.core :as str

niwinz 2024-08-13T16:25:24.683709Z

What I find strangest is: if I remove the json/encode and json/decode from the roundtrip, it works

niwinz 2024-08-13T16:25:37.918459Z

(just discovered that)

niwinz 2024-08-13T16:31:09.836209Z

I think I have discovered the problem here, the problem is on the :multi decode/string It looks for :type expecting it to be decoded but in this phase the type is still a string

niwinz 2024-08-13T16:32:55.154509Z

In any case i'm expecting key-transformer doing it's work before anything other is happens, but it is clearly that I'm wrong here

ikitommi 2024-08-13T16:46:07.954479Z

you have :decode/string in :multi , you don’t have a :string decoder in the chain

ikitommi 2024-08-13T16:47:14.823789Z

there should be a visual debugger for these 😅

niwinz 2024-08-13T16:48:05.914159Z

yep, that fixed the issue, but it was not evident hehe

niwinz 2024-08-13T16:48:43.982439Z

because I expect the key-transformer run before other transformers, so all keys recursivelly on the designated types transformed

ikitommi 2024-08-13T16:50:01.019729Z

yeah, but :multi doesn’t know which branch it should use. branches could be of different types, e.g. :map, :vector, :int etc.

niwinz 2024-08-13T16:50:06.590209Z

with that assumption, Even if the string decoder does not run, i expected the case is transformed. But now I undertand that transformer uses the schema for walking the data, not the data, and with not being unable to proceed down with multi

☝️ 1
ikitommi 2024-08-13T16:50:19.711709Z

first have to resolve the branch, then it sees the map within and runs the key-transformring

niwinz 2024-08-13T16:50:41.609979Z

yep, I understand, thanks for your time

👍 1