Fork me on GitHub
#asami
<
2022-03-19
>
Jakub Holý (HolyJak)11:03:07

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!

quoll11:03:02

Hmmmm. No. It seems OK, which suggests a bug. I'll get onto that today

Jakub Holý (HolyJak)16:03:56

Thank you very much!

Jakub Holý (HolyJak)18:03:45

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])]

quoll21:03:54

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

quoll21:03:51

Oh good... I was able to duplicate it 🙂

quoll22:03:45

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

❤️ 1
quoll22:03:19

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)}))

👍 1
quoll23:03:04

If anyone is curious, it was caused by me being silly: https://twitter.com/quoll/status/1505316312821731331

Jakub Holý (HolyJak)16:03:46

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? 🙏

quoll16:03:59

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])

dharrigan17:03:30

Listened to your podcast on ClojureStream, very interesting!

quoll17:03:58

Uh... thank you 🙂 I never know what I say on those things. I worry that I sound like an idiot! :rolling_on_the_floor_laughing:

dharrigan17:03:29

Not at all. It was all very very interesting! 🙂

❤️ 1
jjttjj20:03:03

Seconded, that was interesting

Jakub Holý (HolyJak)18:03:45

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])]

quoll20:03:31

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.

👍 1
Jakub Holý (HolyJak)20:03:49

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,

quoll20:03:12

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)

quoll20:03:16

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)