-
-
Notifications
You must be signed in to change notification settings - Fork 10
/
diff.cljc
58 lines (50 loc) · 1.24 KB
/
diff.cljc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
(ns fulcro.inspect.lib.diff
(:require [clojure.spec.alpha :as s]))
(s/def ::updates map?)
(s/def ::removals vector?)
(defn updates [a b]
(reduce
(fn [adds [k v]]
(let [va (get a k ::unset)]
(if (= v va)
adds
(if (and (map? v) (map? va))
(assoc adds k (updates va v))
(assoc adds k v)))))
{}
b))
(defn removals [a b]
(reduce
(fn [rems [k v]]
(if-let [[_ vb] (find b k)]
(if (and (map? v) (map? vb) (not= v vb))
(let [childs (removals v vb)]
(if (seq childs)
(conj rems {k childs})
rems))
rems)
(conj rems k)))
[]
a))
(defn diff [a b]
{::updates (updates a b)
::removals (removals a b)})
(defn deep-merge [x y]
(if (and (map? x) (map? y))
(merge-with deep-merge x y)
y))
(defn patch-updates [x {::keys [updates]}]
(merge-with deep-merge x updates))
(defn patch-removals [x {::keys [removals]}]
(reduce
(fn [final rem]
(if (map? rem)
(let [[k v] (first rem)]
(update final k #(patch-removals % {::removals v})))
(dissoc final rem)))
x
removals))
(defn patch [x diff]
(-> x
(patch-updates diff)
(patch-removals diff)))