Skip to content

Commit

Permalink
DB isolation improved to allow db sharing between multiple interpreters
Browse files Browse the repository at this point in the history
  • Loading branch information
MaximGB committed Oct 19, 2020
1 parent 9aada7b commit ab626d0
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 7 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ ifdef::env-github[]
:warning-caption: :warning
endif::[]

== 1.4.0
- Added ability for multiple interpreters to share the same isolated re-frame db part.

== 1.3.2
- Bugfixing release, in 1.3.1 state wasn't properly keywordized, deep states weren't taken into account

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<artifactId>re-state</artifactId>

<version>1.3.2</version>
<version>1.4.0</version>

<name>re-state</name>

Expand Down
16 changes: 12 additions & 4 deletions src/cljs/maximgb/re_state/impl/interpreter.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,14 @@
:before (fn [re-ctx]
(let [interpreter (utils/re-ctx->*interpreter re-ctx)
interpreter-path (protocols/interpreter->path interpreter)
interpreter-id (protocols/interpreter->id interpreter)
db (rf/get-coeffect re-ctx :db)
idb (get-in db interpreter-path)]
(if (or (nil? idb) (and (associative? idb) (not (indexed? idb))))
;; If isolated interpreter db part allows associtiation by keyword
(let [interpreter-state (protocols/interpreter->state interpreter)
new-db (assoc-in db
(conj interpreter-path :state)
(conj interpreter-path interpreter-id)
(.-value ^js/XState.State interpreter-state))]
(-> re-ctx
(rf/assoc-coeffect :db new-db)
Expand All @@ -153,7 +154,7 @@


(defn- interpreter-
[path machine]
[path machine id]
(let [*interpreter (volatile! {:state nil
:started? false})]
(reify
Expand All @@ -163,6 +164,9 @@

protocols/InterpreterProto

(interpreter->id [this]
id)

(interpreter->path [this]
path)

Expand Down Expand Up @@ -235,8 +239,12 @@
(interpreter! nil machine))

([path machine]
(let [valid-path (or path (gensym ::instance))]
(interpreter! path machine (gensym ::instance)))

([path machine id]
(let [valid-path (or path id)]
(interpreter- (if (seqable? valid-path)
valid-path
[valid-path])
machine))))
machine
id))))
2 changes: 2 additions & 0 deletions src/cljs/maximgb/re_state/protocols.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

(defprotocol InterpreterProto
"XState based interpreter protocol which uses re-frame facilities to send/recieve and handle events"
(interpreter->id [this]
"Returns interpreter id.")
(interpreter->path [this]
"Returns interpreter data path in app-db.")
(interpreter->machine ^Machine [this]
Expand Down
4 changes: 2 additions & 2 deletions src/cljs/maximgb/re_state/subscriptions.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@
:maximgb.re-state.core/sub-interpreter-state
(fn [[_ interpreter]]
(isubscribe-root interpreter))
(fn [idb [_ _ keywordize?]]
(let [state (:state idb)]
(fn [idb [_ interpreter keywordize?]]
(let [state (get idb (protocols/interpreter->id interpreter))]
(if keywordize?
(utils/keywordize-state state)
(js->clj state)))))
Expand Down
70 changes: 70 additions & 0 deletions test/maximgb/re_state/shared_db_test.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
(ns maximgb.re-state.shared-db-test
(:require [cljs.test :refer [deftest is testing async use-fixtures]]
[cljs.core.async :as casync]
[re-frame.core :as rf]
[maximgb.re-state.core :refer [machine
interpreter!
interpreter-start!
interpreter-send!
isubscribe-state
def-action-idb
def-action-ifx
let-machine->]
:include-macros true]
[cljs.core.async :as async]))


(def rf-checkpoint (volatile! nil))


(use-fixtures
:each
{:before (fn [] (vreset! rf-checkpoint (rf/make-restore-fn)))
:after (fn [] (@rf-checkpoint))})


(deftest shared-db-test
(testing "Ability of multiper interpreters to share same isolated re-frame db part"
(async done
(let [c (casync/timeout 100)

m1 (let-machine-> {:id :machine-1
:initial :ready-1
:states {:ready-1 {:entry [:store-a :notify-c]}}}
(def-action-idb
:store-a
(fn [db]
(assoc db :a :a)))

(def-action-ifx
:notify-c
(fn []
(async/put! c :ready-1))))

m2 (let-machine-> {:id :machine-2
:initial :ready-2
:states {:ready-2 {:entry [:store-b :notify-c]}}}
(def-action-idb
:store-b
(fn [db]
(assoc db :b :b)))

(def-action-ifx
:notify-c
(fn []
(async/put! c :ready-2))))

i1 (interpreter! [] m1)
i2 (interpreter! [] m2)

s1 (isubscribe-state i1)
s2 (isubscribe-state i2)]
(interpreter-start! i1)
(interpreter-start! i2)

(async/go
(async/<! c)
(async/<! c)
(is (= @s1 :ready-1))
(is (= @s2 :ready-2))
(done))))))

0 comments on commit ab626d0

Please sign in to comment.