Before opening an issue, I wanted to ask first if this change makes sense. I changed the -transform-map-keys implementation to the following on my own code:
(defn -transform-map-keys
[f]
(fn [o]
(if (map? o)
(reduce-kv (fn [res k v]
(let [k' (f k)]
(if (= k k')
res
(-> res
(assoc k' v)
(dissoc k)))))
o
o)
o)))
The current implementation in maili, if you pass a record to decode with the key-transformer, it will replace the record with a map thanks to (into {} (map (.... Changing the impl to use reduce-kv preserves the type. Does it make sense that there would be an issue or even a PR?O maybe a way to pass a custom function to key-transformer and leave the current behavior as default but give the ability to replace it
I consider it as a bug that Records are flattened to maps with the key-transformers.
PR welcome, but I think the reduce-kv is slower than the current transducer. Maybe have special handling for record?, e.g.
(cond
(record?) reduce-kv
(map?) transducer
:else default)
better to run perf-tests on these to make sure how they perform
it seems the reduce-kv is slower with plain maps, current:
Evaluation count : 3503592 in 6 samples of 583932 calls.
Execution time mean : 168,090682 ns
Execution time std-deviation : 0,712479 ns
Execution time lower quantile : 167,320484 ns ( 2,5%)
Execution time upper quantile : 169,110612 ns (97,5%)
Overhead used : 1,801948 ns
new:
Evaluation count : 2250630 in 6 samples of 375105 calls.
Execution time mean : 273,808160 ns
Execution time std-deviation : 6,733026 ns
Execution time lower quantile : 266,023063 ns ( 2,5%)
Execution time upper quantile : 282,614571 ns (97,5%)
Overhead used : 1,801948 nsso, this should be just for record? s. PR welsome!
if one would not touch the keys, your approach would be much faster, as it would not assoc-dissoc anything, current:
Execution time mean : 109,704440 ns
Execution time std-deviation : 0,840514 ns
Execution time lower quantile : 108,709907 ns ( 2,5%)
Execution time upper quantile : 110,634955 ns (97,5%)
Overhead used : 1,801948 ns
new:
Execution time mean : 8,723063 ns
Execution time std-deviation : 0,501256 ns
Execution time lower quantile : 8,447378 ns ( 2,5%)
Execution time upper quantile : 9,581723 ns (97,5%)
Overhead used : 1,801948 ns… but don’t think that is the common case (of not transforming the keys, e.g. running identity on keys).
I finally ended up with a specific impl for record and for map
I will do a PR this days
Did you test with a transient map?
I have used transient map on my code, so I try to test it before PR.