Skip to content

Instantly share code, notes, and snippets.

@henryw-erudine
Created February 17, 2015 09:45
Show Gist options
  • Save henryw-erudine/73cbcdea1eda150e78da to your computer and use it in GitHub Desktop.
Save henryw-erudine/73cbcdea1eda150e78da to your computer and use it in GitHub Desktop.
(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