From 057c6ddc0df47331de9d7dd7977317e8e54cb1e6 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 14 Apr 2026 20:04:36 +0000 Subject: [PATCH] :bug: Fix deep-mapm double-applying mfn on leaf entries The deep-mapm function was applying the mapping function twice on leaf entries (non-map, non-vector values): once when destructuring the entry, and again on the already-transformed result in the else branch. Now mfn is applied exactly once per entry. --- common/src/app/common/data.cljc | 7 ++----- common/test/common_tests/data_test.cljc | 17 ++++++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index 7f59c14ad6..93d66780f5 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -602,12 +602,9 @@ (let [do-map (fn [entry] (let [[k v] (mfn entry)] - (cond - (or (vector? v) (map? v)) + (if (or (vector? v) (map? v)) [k (deep-mapm mfn v)] - - :else - (mfn [k v]))))] + [k v])))] (cond (map? m) (into {} (map do-map) m) diff --git a/common/test/common_tests/data_test.cljc b/common/test/common_tests/data_test.cljc index 873f0bb7d1..7cad2da911 100644 --- a/common/test/common_tests/data_test.cljc +++ b/common/test/common_tests/data_test.cljc @@ -538,17 +538,20 @@ (into [] (d/distinct-xf :id) [{:id 1 :v "a"} {:id 2 :v "x"} {:id 2 :v "b"}])))) (t/deftest deep-mapm-test - ;; Note: mfn is called twice on leaf entries (once initially, once again - ;; after checking if the value is a map/vector), so a doubling fn applied - ;; to value 1 gives 1*2*2=4. - (t/is (= {:a 4 :b {:c 8}} + ;; mfn is applied once per entry + (t/is (= {:a 2 :b {:c 4}} (d/deep-mapm (fn [[k v]] [k (if (number? v) (* v 2) v)]) {:a 1 :b {:c 2}}))) - ;; Keyword renaming: keys are also transformed — and applied twice. - ;; Use an idempotent key transformation (uppercase once = uppercase twice). + ;; Keyword renaming: keys are transformed once per entry (let [result (d/deep-mapm (fn [[k v]] [(keyword (str (name k) "!")) v]) {:a 1})] - (t/is (contains? result (keyword "a!!"))))) + (t/is (contains? result (keyword "a!")))) + ;; Vectors inside maps are recursed into + (t/is (= {:items [{:x 10}]} + (d/deep-mapm (fn [[k v]] [k (if (number? v) (* v 10) v)]) + {:items [{:x 1}]}))) + ;; Plain scalar at top level map + (t/is (= {:a "hello"} (d/deep-mapm identity {:a "hello"})))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Numeric helpers