malli icon indicating copy to clipboard operation
malli copied to clipboard

Json decoder doesn't convert :map key strings to keywords

Open Deraen opened this issue 3 years ago • 2 comments

(m/decode [:map [:user-id :string]] {"user-id" "foo"} mt/json-transformer)
;; => {"user-id" "foo"}

(m/decode [:map-of :keyword :string] {"user-id" "foo"} mt/json-transformer)
;; => {:user-id "foo"}

I think the first one should work, similar to :map-of. I guess Malli is just missing :map decoder which is aware of map keys?

Deraen avatar Nov 10 '21 11:11 Deraen

Thank you for opening the issue @Deraen Could you point to the code that needs to be fixed. Take into consideration that it's my first look into Malli code base.

viebel avatar Nov 10 '21 11:11 viebel

Simplified json-transformer with :map decoder. But this has performance considerations because this will run for every :map schema in the value being decoded:

(defn json-transformer
  ([] (json-transformer nil))
  ([{::keys [json-vectors]}]
   (mt/transformer
     {:name :json
      :decoders (-> (mt/-json-decoders)
                    ;; Missing :map-of from existing json-transformer
                    (assoc :map {:compile (fn [schema _]
                                            (fn [value]
                                              (reduce (fn [v k]
                                                        (if (contains? v k)
                                                          v
                                                          ;; If map contains value for the key but with key as string,
                                                          ;; replace the name.
                                                          (if-let [x (get v (name k))]
                                                            (-> v
                                                                (assoc k x)
                                                                (dissoc (name k)))
                                                            v)))
                                                      value
                                                      ;; List of :map keys
                                                      (map first (m/entries schema)))))})
                    (cond-> json-vectors (assoc :vector mt/-sequential->vector)))
      :encoders (mt/-json-encoders)})))

TODO: Namespaced keys and other possible corner cases with keywords.

https://github.com/metosin/malli/blob/master/src/malli/transform.cljc#L339-L351 Will need to implement something similar (but hopefully more performant.)

Deraen avatar Nov 10 '21 11:11 Deraen