metosin / malli

High-performance data-driven data specification library for Clojure/Script.
Eclipse Public License 2.0
1.46k stars 208 forks source link

Failure to decode `:enums` having keywords #819

Closed billtuba closed 1 year ago

billtuba commented 1 year ago

Found in version : 0.10.0 Previously working in : 0.9.2

Reproducible in master : yes Given schema:

(def Test [:map-of
           [:enum {:encode/json name
                   :decode/json keyword}
            :a :b :c]
           int?])

When I run this:

(let [m (mg/generate Test)
      encoded (m/encode Test m mt/json-transformer)
      decoded (m/decode Test encoded mt/json-transformer)]
  {:generated m
   :encoded encoded
   :decoded decoded})

decode under v0.9.2 behaves properly:

;; => {:generated {:b 621, :a 403, :c -14}, 
          :encoded {"b" 621, "a" 403, "c" -14},
          :decoded {:b 621, :a 403, :c -14}}

decode using v 0.10.0 does not:

;; => {:generated {:b -3, :a -191, :c -1}, 
          :encoded {"b" -3, "a" -191, "c" -1},
          :decoded {nil -1}} ;;; <<< here's the problem

transforming_enums.clj.zip

N.B. If remove/comment out the :enum/:= entries in -json-decoders the code behaves as expected.

ikitommi commented 1 year ago

Oh, I see. This is a bug. We are composing :map-of transformers via m/-comp and it has worked before as everything was defined as a function. :enum transformer is a real interceptor, so we should compose it with m/-intercepting. This should be easy to fix.

That said, I think the :map-of transformer is not working correctly anyways as it currently forcefully transforms keys into strings first, giving wrong results:

(m/decode
 [:map-of :int :int]
 {:kikka :kukka}
 (mt/json-transformer))
; => {"kikka" :kukka}

Like :or, it should validate the results after applying key transformation, if not valid, keep the original value.

opqdonut commented 1 year ago

849 is a fix for the original bug. I'll see if I can also fix the thing @ikitommi mentioned just now.

opqdonut commented 1 year ago

Fixed the thing ikitommi mentioned. New behaviour:

(m/decode
 [:map-of :int :int]
 {:kikka :kukka}
 (mt/json-transformer))
; => {:kikka :kukka}
billtuba commented 1 year ago

Thanks for getting this in!