Skip to content

Instantly share code, notes, and snippets.

@jarppe
Last active November 17, 2016 18:24
Show Gist options
  • Save jarppe/7a7b3234b6ce0b704df8046c67aad988 to your computer and use it in GitHub Desktop.
Save jarppe/7a7b3234b6ce0b704df8046c67aad988 to your computer and use it in GitHub Desktop.
Return all transactions and all their datoms that have contributed to given entity
(ns datomic-spike.audit-trail
(:require [datomic.api :as d]))
(defn entity-txs
"Accepts an entity, returns all transactions (as entities) that
have altered the given entity, sorted by transaction t"
[e]
(let [id (:db/id e)
db (d/entity-db e)
history (d/history db)]
(->> (d/q '[:find [?tx ...]
:in $ ?e
:where [?e _ _ ?tx]]
history
id)
(sort-by d/tx->t)
(map (partial d/entity db)))))
(defn tx-datoms
"Accepts a connection and an entity of transaction. Returns all
datoms of given transaction entity"
[conn tx]
(let [log (d/log conn)
tx-id (:db/id tx)]
(d/q '[:find ?e ?a ?v ?op
:in ?log ?tx
:where [(tx-data ?log ?tx) [[?e ?a ?v _ ?op]]]]
log
tx-id)))
(defn entity-audit-trail
"Accepts a connection and an entity. Returns a seq of vectors of
two elements, a transaction entity and a seq of datoms of the
transaction. Transactions are entities and are ordered by
transaction t."
[conn e]
(->> (entity-txs e)
(map (fn [tx]
[tx (tx-datoms conn tx)]))))
(comment
(def uri (format "datomic:mem://test-%s" (d/squuid)))
(d/create-database uri)
(def c (d/connect uri))
(do @(d/transact c [{:db/id (d/tempid :db.part/db)
:db/ident :audit/user
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id (d/tempid :db.part/db)
:db/ident :person/name
:db/valueType :db.type/string
:db/unique :db.unique/value
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id (d/tempid :db.part/db)
:db/ident :person/email
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id (d/tempid :db.part/db)
:db/ident :person/tel
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}])
@(d/transact c [{:db/id (d/tempid :db.part/user -1)
:person/name "Jarppe"
:person/email "[email protected]"}
[:db/add (d/tempid :db.part/tx) :audit/user "Matti"]])
@(d/transact c [{:db/id [:person/name "Jarppe"]
:person/email "[email protected]"}
[:db/add (d/tempid :db.part/tx) :audit/user "Jarppe"]])
@(d/transact c [{:db/id [:person/name "Jarppe"]
:person/tel "1234"}
[:db/add (d/tempid :db.part/tx) :audit/user "Matti"]])
@(d/transact c [{:db/id [:person/name "Jarppe"]
:person/email "[email protected]"
:person/tel "321"}
[:db/add (d/tempid :db.part/tx) :audit/user "Petri"]])
@(d/transact c [[:db/retract [:person/name "Jarppe"] :person/tel "321"]
[:db/add [:person/name "Jarppe"] :person/email "[email protected]"]
[:db/add (d/tempid :db.part/tx) :audit/user "Mikko"]]))
(entity-audit-trail c (d/entity (d/db c) [:person/name "Jarppe"]))
(let [db (d/db c)
audit-trail (entity-audit-trail conn (d/entity db [:person/name "Jarppe"]))]
(doseq [[{:keys [:db/txInstant :audit/user]} datoms] audit-trail]
(println txInstant user)
(doseq [[e a v op] datoms]
(println " "
e
(->> a (d/entity db) :db/ident)
(pr-str v)
(if op "add" "retract")))))
; Prints:
; #inst "2016-11-17T18:12:19.625-00:00" Matti
; 17592186045418 :person/name "Jarppe" add
; 17592186045418 :person/email "[email protected]" add
; 13194139534313 :audit/user "Matti" add
; 13194139534313 :db/txInstant #inst "2016-11-17T18:12:19.625-00:00" add
; #inst "2016-11-17T18:12:19.627-00:00" Jarppe
; 17592186045418 :person/email "[email protected]" retract
; 13194139534315 :db/txInstant #inst "2016-11-17T18:12:19.627-00:00" add
; 13194139534315 :audit/user "Jarppe" add
; 17592186045418 :person/email "[email protected]" add
; #inst "2016-11-17T18:12:19.628-00:00" Matti
; 17592186045418 :person/tel "1234" add
; 13194139534316 :audit/user "Matti" add
; 13194139534316 :db/txInstant #inst "2016-11-17T18:12:19.628-00:00" add
; #inst "2016-11-17T18:12:19.629-00:00" Petri
; 17592186045418 :person/email "[email protected]" retract
; 17592186045418 :person/tel "321" add
; 17592186045418 :person/email "[email protected]" add
; 13194139534317 :db/txInstant #inst "2016-11-17T18:12:19.629-00:00" add
; 13194139534317 :audit/user "Petri" add
; 17592186045418 :person/tel "1234" retract
; #inst "2016-11-17T18:12:19.631-00:00" Mikko
; 13194139534318 :db/txInstant #inst "2016-11-17T18:12:19.631-00:00" add
; 13194139534318 :audit/user "Mikko" add
; 17592186045418 :person/email "[email protected]" add
; 17592186045418 :person/tel "321" retract
; 17592186045418 :person/email "[email protected]" retract
(d/release c)
(d/delete-database uri)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment