I wanted to write a function that would expand everything that is reachable from a given Datomic Entity. I am aware that this might be problematic if there are cycles, assume that entity is not cyclic.
(defn touch-all
"Touches `entity and all other reachable Entities of `entity"
[entity]
(let [entity (d/touch entity)]
(doseq [[k v] entity]
(when (instance? datomic.query.EntityMap v)
(touch-all v)))
entity))
d/touch
expands out all "keys" in the entity and displays their values as either their literal value or as another (untouched) entity.
The code above does walk through all children (recursive) of entity. Therefore all entities reachable from the entity
have been touched. Why am I not seeing the entity in its fully child expanded form when I type (touch-all entity)
?
A large part of my confusion has to do with what I see in the repl:
sample.datomic> (def root (d/entity db 44))
#'sample.datomic/root
sample.datomic> root
{:db/id 17592186045421}
sample.datomic> (:answer-2-card root)
{:db/id 17592186045423}
sample.datomic> root
{:answer-2-card {:db/id 17592186045423}, :db/id 17592186045421}
sample.datomic> (-> root :answer-2-card :text)
"Card 2"
sample.datomic> (-> root :answer-2-card)
{:text "Card 2", :db/id 17592186045423}
sample.datomic> root
{:answer-2-card {:text "Card 2", :db/id 17592186045423}, :db/id 17592186045421}
So, it really looks like the Entities are mutable and sticky. When I access entities within containing entities, it appears to effect the string representation of the containing attribute as well. If this works manually "recursively" in the repl, why does it not work when I do it in a function? I am just confused because I don't seem to be able to repeat what I can manually do in the repl within a function. Seems odd.
The answer to your question is immutability.
entity
is bound to the first touched entity passed by parameter, but that value doesn't change when the recursion touches other entities.If you want a single value containing a tree of touched entities you should do something like:
With the following considerations:
assoc
fails on entities.ref
and cardinalitymany
(in that case, whene
is aset
it should be considered it could be a set of entities)