add merge-fx macro
this macro allows safe merging of cofx, making complex events easier to understand while avoiding the risk to overwrite the db effect when threading multiple effects creating functions Signed-off-by: Eric Dvorsak <eric@dvorsak.fr>
This commit is contained in:
parent
b1ce44af3a
commit
8b1288e20b
|
@ -16,3 +16,56 @@
|
||||||
~new-db
|
~new-db
|
||||||
~db))) forms))]
|
~db))) forms))]
|
||||||
~db))))
|
~db))))
|
||||||
|
|
||||||
|
(defmacro merge-fx*
|
||||||
|
"This macro is called recursively from merge-fx
|
||||||
|
It wraps each form in a let binding that captures
|
||||||
|
- the new co-effect after updating the db key if a db effect was in the map returned
|
||||||
|
by the previous form
|
||||||
|
- the new fx map after merging previous fx map with the map returned by the previous form
|
||||||
|
We use safe-merge for that which is returning a map with a :merging-fx-with-common-keys effect
|
||||||
|
in case at least one effect that is not a :db effect was overwritten by merge"
|
||||||
|
{:added "1.0"}
|
||||||
|
[fx cofx & forms]
|
||||||
|
(if forms
|
||||||
|
(let [form (first forms)
|
||||||
|
temp-cofx (gensym 'temp-cofx)]
|
||||||
|
`(let [~temp-cofx (update-db ~cofx ~fx)
|
||||||
|
fx# (safe-merge ~fx ~(with-meta `(~(first form) ~@(next form) ~temp-cofx) (meta form)))]
|
||||||
|
(merge-fx* fx# ~temp-cofx ~@(next forms))))
|
||||||
|
fx))
|
||||||
|
|
||||||
|
(defmacro merge-fx
|
||||||
|
"Takes a map of co-effects and forms as argument.
|
||||||
|
The first optional form can be map of effects/
|
||||||
|
The next forms are functions applying effects and returning a map of effects.
|
||||||
|
The macro ensures that updates to db are passed from function to function within the cofx :db key and
|
||||||
|
that only a :merging-fx-with-common-keys effect is returned if some functions are trying
|
||||||
|
to produce the same effects (excepted :db effect)"
|
||||||
|
{:added "1.0"}
|
||||||
|
[cofx & forms]
|
||||||
|
(let [form (first forms)]
|
||||||
|
(if (or (symbol? form)
|
||||||
|
(map? form))
|
||||||
|
`(merge-fx* ~form ~cofx ~@(next forms))
|
||||||
|
`(merge-fx* {} ~cofx ~@forms))))
|
||||||
|
|
||||||
|
(comment (defn fn1 [{:keys [db]} ]
|
||||||
|
{:db (assoc db :a 0)
|
||||||
|
:a "1"})
|
||||||
|
|
||||||
|
(defn fn2 [ a {:keys [db]}]
|
||||||
|
{:db (update db :a + a)
|
||||||
|
})
|
||||||
|
|
||||||
|
(defn fn3 [ a {:keys [db u]}]
|
||||||
|
{:db (update db :a + u)})
|
||||||
|
|
||||||
|
(let [a 1
|
||||||
|
b 2
|
||||||
|
cofx {:db {} :u 1}]
|
||||||
|
(merge-fx cofx
|
||||||
|
{:db {:hello 2}}
|
||||||
|
(fn1)
|
||||||
|
(fn2 a)
|
||||||
|
(fn3 b))))
|
||||||
|
|
|
@ -107,3 +107,17 @@
|
||||||
(remove (fn [{:keys [dapp? pending?]}]
|
(remove (fn [{:keys [dapp? pending?]}]
|
||||||
(or pending? dapp?)))
|
(or pending? dapp?)))
|
||||||
(map :whisper-identity)))
|
(map :whisper-identity)))
|
||||||
|
|
||||||
|
(defn update-db [cofx fx]
|
||||||
|
(if-let [db (:db fx)]
|
||||||
|
(assoc cofx :db db)
|
||||||
|
cofx))
|
||||||
|
|
||||||
|
(defn safe-merge [fx new-fx]
|
||||||
|
(if (:merging-fx-with-common-keys fx)
|
||||||
|
fx
|
||||||
|
(let [common-keys (clojure.set/intersection (into #{} (keys fx))
|
||||||
|
(into #{} (keys new-fx)))]
|
||||||
|
(if (empty? (disj common-keys :db))
|
||||||
|
(merge fx new-fx)
|
||||||
|
{:merging-fx-with-common-keys common-keys}))))
|
||||||
|
|
Loading…
Reference in New Issue