Hello! I am trying to retract entity's attributes but it fails with the following error, that I do not understand:
> Unexpected encoding of internal node
> :data {:node #a/n[3]}
The code (using a local storage):
(defn retract-entity [db id]
(d/transact
db
(d/q '[:find :db/retract ?e ?a ?v :where [?e ?a ?v] [?e :id ?id] :in $ ?id]
db id)))
And it produces a sequence of ([:db/retract #a/n[3] :b false] ...) .
Any tips what am I doing wrong? Thank you!Hmmmm. No. It seems OK, which suggests a bug. I'll get onto that today
Thank you very much!
I am wondering whether it might be better to be more specific with the attribute filter and instead of saying "I want any of these attributes" say "for each of the entities, I want these attributes", i.e. something like:
'[:find ?e ?a ?v
:where [?e ?a ?v]
;; TODO how to say that the output ?e is either of ?o, ?p ?
[?o :order/product ?p] ; we are interested in an order and its product
;; Filter the attributes of order and product we want:
(or [?o :order/descr ?v]
[?p :product/name ?v])]This is definitely an unexpected bug. The place where your error occurs can only be called when the node could not be "encapsulated" into a long value. But it's an internal node, and they can always be encapsulated into a long value. So I don't know how this code can ever be called!?! I'm trying to duplicate it here, but I'd love a stack trace
Oh good... I was able to duplicate it 🙂
OK. I found my problem. I tried to do something clever, and I did not realize that Clojure does something cleverer.
Anyway, a fix will be in the next release. Meanwhile, the solution is to wrap the result in a map with the key :tx-data
i.e.
(defn retract-entity [db id]
(d/transact
db
{:tx-data
(d/q '[:find :db/retract ?e ?a ?v :where [?e ?a ?v] [?e :id ?id] :in $ ?id]
db id)}))
If anyone is curious, it was caused by me being silly: https://twitter.com/quoll/status/1505316312821731331
Thanks a lot!
Another question: I want to simulate pull, namely to get some attributes of an entity (an Order) and some attributes of another entity related to it (a Product, linked to via order's :order/product ). The query to get the data (which I can assemble into the desired data tree) I came up with is this:
(d/q '[:find ?e ?a ?v
:where [?e ?a ?v]
(or [?e :order/product] ; the entities I want = either the parent entity or the linked-to entity
[_ :order/product ?e])
[(contains? #{:order/descr :product/name} ?a)]] ; the subset of the attributes I want
d)
which seems to work. Is it indeed a good solution? 🙏This will work, but I'd probably bind ?a instead of using a filter:
(d/q '[:find ?e ?a ?v
:in $ [?a ...]
:where [?e ?a ?v]
(or [?e :order/product]
[_ :order/product ?e])]
d [:order/descr :product/name])
Ah, thanks a lot!
Listened to your podcast on ClojureStream, very interesting!
Uh... thank you 🙂 I never know what I say on those things. I worry that I sound like an idiot! 🤣
Not at all. It was all very very interesting! 🙂
Seconded, that was interesting
I'm not quite sure of what you're trying to find here, but going on the description...
(a/q '[:find ?e ?a ?v
:in $ [?a ...]
:where
[?e ?a ?v]
(or [?e :order/product _]
[_ :order/product ?e])]
db [:order/descr :product/name])
This does try to look for the :order/descr attributes on products and the :product/name attribute on orders, but that's actually cheap, and probably cheaper than anything else.Thank you!
> I'm not quite sure of what you're trying to find here
To explain: I am making an Asami adapter for the #fulcro Rapid Application Development library and thus, given an EDN Query Language (EQL) query such as [:order/id :order/descr {:order/product [:product/id :product/name]}] I need to return the corresponding data (in this case something like {:order/id 1, :order/descr "Buy ETH", :order/product {:product/id 101, :product/name "Ether"}} ). In Datomic it is achieved by a trivial translation of the EQL to a Datomic pull syntax. So I essentially need to implement something like Pull on top of Asami. My idea was to write a query that fetches all the relevant EAV triplets and (re)construct the desired data tree from that,
One possibility, but I don't know if it will be faster...
(a/q '[:find ?e ?a ?v
:where
[?e ?a ?v]
(or (and [(identity :order/descr) ?a] [?e :order/product _])
(and [(identity :product/name) ?a] [_ :order/product ?e]))]
db)
This actually shows me a limitation of bindings. They're expecting a function call to set a variable, and can't take an expression (which is why it needs to wrap the keyword in a call to identity)