Forked from henryw-erudine/datascript-to-datomic-util.cljs
Created
August 3, 2016 18:24
-
-
Save christianromney/3377599b21d5e1174ef174b7e45d7715 to your computer and use it in GitHub Desktop.
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 datascript-to-datomic-util | |
(:require [datascript :as d])) | |
;;;; a utility to help with a datomic-datascript roundtrip process involving: | |
;;; 1. export some data from a datomic database and transact into a datascript instance. | |
;;; 2. perform one or more transactions against datascript. | |
;;; 3. transact the sum of all changes made against datascript back into datomic in a single tx | |
;;; this namespace contains two public functions: | |
;;; listen-for-changes: listen to datascript transactions and build up a record of changes | |
;;; export-sum-of-deltas-as-tx-data: export the changes from datascript into a format suitable for transacting back into datomic | |
;;; Constraints: | |
;;; 1. datascript db and datomic db share a schema | |
;;; 2. maintain entity ids from datomic when exporting to datascript. For example, here is some data exported from | |
;;; datomic | |
;;; [{:db/id 123456789 | |
;;; :db/doc "something"}] | |
;;; The :db/id is the internal entity id from datomic and when this data is transacted into datascript, | |
;;; that id will be preserved. when making the return trip, datomic will | |
;;; make changes against the entities identified by their internal ids. | |
(defn- get-changes-id | |
"the id an entity is tracked by is either its original internal id from datomic or | |
the negative of the one assigned by datascript. this is done in order to distinguish new | |
things from changed things when transacting back into datomic" | |
[new-entities-in-tx changeval v] | |
(cond | |
(new-entities-in-tx v) (- 0 v) | |
(changeval (- 0 v)) (- 0 v) | |
:else v)) | |
(def bool->op | |
{true :db/add | |
false :db/retract}) | |
(defn- assimilate-new-tx [sum-deltas tx-report] | |
(when-not (get-in tx-report [:tx-meta :from-datomic]) | |
(let [get-stable-entity-id (->> tx-report | |
:tempids | |
vals | |
set | |
(partial get-changes-id)) | |
reference-attribute? (->> tx-report | |
:db-after | |
:schema | |
(filter (fn [[k v]] (= :db.type/ref (:db/valueType v)))) | |
(map first) | |
set)] | |
(reduce | |
(fn [result {:keys [e a v tx added]}] | |
(assoc-in result [(get-stable-entity-id result e) | |
a | |
(if-not (reference-attribute? a) | |
v | |
(get-stable-entity-id result v))] | |
(bool->op added))) | |
sum-deltas | |
(:tx-data tx-report))))) | |
(defn- record-change! [changes tx-report] | |
(swap! changes assimilate-new-tx tx-report)) | |
(defn export-sum-of-deltas-as-tx-data | |
"generate data suitable for transacting into datomic/datascript. | |
For datomic, the result of this function can be walked, transforming negative | |
entity ids into datomic temp ids. | |
changeval is the current value of the atom used to record changes" | |
[changeval] | |
(for [[e as] changeval | |
[a vs] as | |
[v op] vs] | |
[op e a v])) | |
(defn listen-for-changes | |
"start recording changes. | |
params are datascript connection and an atom containing empty map" | |
[conn change-recorder] | |
(d/listen! conn (partial record-change! change-recorder))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment