Created
June 4, 2025 13:06
-
-
Save SkyWriter/011d4072e335debe4cd4708c0b3f307c to your computer and use it in GitHub Desktop.
An excerpt to use Datascript as Re-Frame database (circa 2015)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns theatralia.thomsky | |
(:require [datascript :as d] | |
datascript.core | |
[cljs-uuid-utils.core :as uuid] | |
[re-frame.core :as rf] | |
[re-frame.handlers :as handlers] | |
[re-frame.middleware :as middleware] | |
[plumbing.core :refer [safe-get]] | |
[reagent.core :as reagent])) | |
(defn set-up-datascript! | |
"Swaps in a Datascript database with schema ?SCHEMA (default: Datascript | |
default schema) for the APP-DB in re-frame. To be used as an event handler." | |
([app-db [_ & [?schema]]] | |
(let [conn (d/create-conn (or ?schema datascript.core/default-schema))] | |
(reset! app-db @conn) | |
(reset-meta! app-db (meta conn))))) | |
;;; Credits: | |
;;; - https://gist.github.com/allgress/11348685, though it isn't complete. See | |
;;; the comments. See here for a bit more discussion: | |
;;; https://groups.google.com/d/topic/clojurescript/o0W57ptvPc8/discussion | |
;;; - https://github.com/Day8/re-frame/blob/master/src/re_frame/middleware.cljs | |
;;; - https://github.com/Day8/re-frame/blob/master/src/re_frame/core.cljs | |
;; Note: | |
;; | |
;; If the application is getting slow, your first step towards a diagnosis | |
;; should be to uncomment the line below and watch in the console when and how | |
;; often bind is called. – If it only gets called as many times as there are | |
;; binds in the code and only on application load, your problem lies somewhere | |
;; else. If it gets called more often than that and while the application runs | |
;; (for example, when you click or type), there are two likely causes: | |
;; | |
;; - You've wrapped a call to bind in a reagent.ratom/reaction. In this case | |
;; bind gets called whenever the app-db changes, which is not what you want. | |
;; | |
;; - You've used a Form-1 component where you should use a Form-2 component. | |
;; See https://github.com/Day8/re-frame/wiki/Creating-Reagent-Components. | |
;; | |
;; If it wasn't repeated bind calls, you might want to exclude scratch changes | |
;; from being checked for novelties. At tag filter-scratch you can find a | |
;; commit that introduced that, but wasn't needed at the time. | |
;; | |
;; TODO: When all the querying gets too slow, we have to introduce some | |
;; cleverness. See the links in the credits above and | |
;; https://github.com/tonsky/datascript/pull/12. (RM 2015-09-17) | |
(defn bind | |
"Returns a ratom containing the result of query Q with the arguments Q-ARGS on | |
the value of the database behind CONN." | |
[q conn & q-args] | |
;(println "bind called" q) ; Commented out on purpose. – See note above. | |
(let [k (uuid/make-random-uuid) | |
state (reagent/atom nil) | |
res (apply d/q q @conn q-args)] | |
(reset! state res) | |
(d/listen! conn k | |
(fn [tx-report] | |
; (println tx-report) | |
(let [new-result (apply d/q q (:db-after tx-report) q-args)] | |
(when (not= new-result @state) | |
(reset! state new-result))))) | |
(set! (.-__key state) k) | |
state)) | |
(defn unbind | |
"Stops changes in CONN from causing updates of ratom STATE." | |
[conn state] | |
(d/unlisten! conn (.-__key state))) | |
(defn pure-datascript | |
"Adaptation of the re-frame middleware 'pure' for Thomsky. | |
The HANDLER wrapped in this middleware will receive the current value behind | |
CONN and has to return a Datascript transaction data structure that will be | |
transact!ed over CONN. | |
So, as opposed to re-frame's 'pure', where the HANDLER has to return a whole | |
new app state, here the HANDLER only returns transaction data that will be | |
used to change the app state." | |
[handler] | |
(fn pure-datascript-handler [conn event-vec] | |
(assert (satisfies? cljs.core/IAtom conn) | |
(str "conn has to be an atom. Got: " conn)) | |
(let [db @conn | |
_ (assert (satisfies? datascript.core.IDB db) | |
(str "@conn has to be a Datascript Database. Got: " db)) | |
txd (handler db event-vec)] | |
(assert (sequential? txd) | |
(str "Handler has to return sequence of transaction data." | |
"Got: " txd)) | |
(d/transact! conn txd)))) | |
(defn register-handler | |
"Handler registration procedure that provides the right defaults for | |
Theatralia. | |
In re-frame, the default handler registration procedure applies only the | |
'pure' middleware to a handler. Here we apply the respective 'pure-datascript' | |
middleware as well as the 'trim-v' middleware, since we never need this silly | |
keyword in our subscription handlers anyway." | |
([id handler] (register-handler id [] handler)) | |
([id middleware handler] | |
(handlers/register-base id | |
[pure-datascript middleware middleware/trim-v] | |
handler))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment