Global state in re-dash is stored in some database.
Usually this database is in-memory only and represented as some data structure, like a map - this is the default behavior.
Other times we might require more capability like persistence, relational queries, replication etc. and want to opt for using a full featured database engine on the client instead, while keeping with the core concepts of the data loop - events, subscriptions etc.
This is achieved by implementing the Database protocol. Out the box, re-dash ships with support for 3 database implementations of this protocol:
Multiple databases may be registered and used in the same app simultaneously. Note however, that subscription signals of mixed database implementations cannot be used within one layer 3 subscription.
The default path based Map Atom.
This Database is registered by default,  always available to query via subscriptions or update via events using the built-in :db effect.
Drift is the relational persistence library for your Dart and Flutter apps - it is an abstraction over sqlite3.
The simplest way (currently) is to maintain the Drift schema in raw .dart files in the /.lib folder directly and have the code generator watch it with dart run build_runner watch.
For more info see the samples/drift/lib/database.dart sample and the drift documentation.
Register it early on in the app startup (like in main)
(await
  (rd/reg-database
    :drift                                 ;; <== Choose any `database-id`
    {:impl     (drift/Drift.)              ;; <== The `Database` protocol implementation
     :instance (database/AppDatabase.)}))  ;; <== The database instance
Use the chosen database-id in reg-sub that should target Drift for example
(rd/reg-sub
  ::app-state
  :drift                               ;; <== The registered database-id
  (fn [^db/AppDatabase db _]
    (.select db (.-appState db))))     ;; <== Query that returns a subsribable (stream)
(rd/reg-sub
  ::width
  :drift
  (fn [_]
    (rd/subscribe [::app-state]))      ;; <== Layer 3 signal(s) supported
  (fn [[^db/AppStateData data] _]
    (.-width data)))
Use the chosen database-id as the effect-id in events.
Note that the event itself does not mutate the database directly, but instead returns a function being passed the database instance. This is keeping with re-dash (& re-frame) methodology of writing pure event handlers - the mutation is applied later when re-dash execute effects.
There is no need to register the :drift (database-id) effect as this is automatically done for you.
(rd/reg-event-fx
    ::increment-width
    (fn [_ [_ width]]
      {:drift #(let [db ^db/AppDatabase %]
                 (.write (.update db (.-appState db))
                         (db/AppStateCompanion
                           .width (-> width inc int d/Value))))}))
There's a working sample app in the samples/drift folder using the Drift database as app state
A popular reactive NoSQL database for JavaScript, somewhat usable from Flutter. It has various storage layer plugins including an in-memory only option.
Maintain the schema in raw JavaScript, and compile it with node.
For more info see the samples/rxdb/javascript/src/index.js sample and the rxdb documentation
Register it  early on in the app startup (like in main)
(await
    (rd/reg-database
      :rxdb                                                          ;; <== Choose any `database-id`
      {:impl     (rx-db/RxDB.)                                       ;; <== The `Database` protocol implementation
       :instance (database/getRxDatabase "javascript/dist/index.js"  ;; <== The database instance
                                         "AppDatabase")}))
Use the chosen database-id in reg-sub that should target RxDB for example
(rd/reg-sub
  ::app-state
  :rxdb                                         ;; <== The registered database-id
  (fn [db [_ selector]]
    (-> (.getCollection db coll-name)
        (.find selector))))                     ;; <== Query that returns a subsribable (stream)
(rd/reg-sub
  ::width
  :rxdb
  (fn [_]
    (rd/subscribe [::app-state]))               ;; <== Layer 3 signal(s) supported
  (fn [[doc] _]
    (get (->> (.-data ^rxdb/RxDocument doc)
              (into {}))
         "width")))
Use the chosen database-id as the effect-id in events.
Note that the event itself does not mutate the database directly, but instead returns a function being passed the database instance. This is keeping with re-dash (& re-frame) methodology of writing pure event handlers - the mutation is applied later when re-dash execute effects.
There is no need to register the :rxdb (database-id) effect as this is automatically done for you.
(rd/reg-event-fx
    ::increment-width
    (fn [_ _]
      {:rxdb #(.insert (.getCollection % coll-name)
                       {"id"    (str (DateTime/now))
                        "width" ((fnil f 0) val)})}))
RxDB for Flutter is experimental, and many features are missing.
Some of the known limitations include:
There's a working sample app in the samples/rxdb folder using the RxDB database as app state
Adding support for another database is a matter of implementing the Database protocol and registering it early on in the app startup, like in main:
(await
  (rd/reg-database
    :my-database-id                    ;; <== Choose any `database-id`
    {:impl     (my/DatabaseImpl.)      ;; <== Instantiate the `Database` protocol implementation
     :instance (some/MyDatabase.)}))   ;; <== Instantiate the database instance
To support subscriptions, the database engine must support some way of watching / observing queries.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs | 
| ← | Move to previous article | 
| → | Move to next article | 
| Ctrl+/ | Jump to the search field |