Fork me on GitHub
#xtdb
<
2023-10-30
>
Olav Fosse04:10:24

Hello everyone I'm following the XTDB tutorial and experimenting a bit with :in clauses I have this query here, which is parameterised on e and item:

(xt/q (xt/db node)
      '{:find [name funds stock item]
        :where [[e :company-name name]
                [e :credits funds]
                [e :units/CH4 stock]]
        :in [[e item]]}
      [:tombaugh-resources :units/CH4])
;; => #{["Tombaugh Resources Ltd." 151 82 :units/CH4]}
However when I try using the item parameter it stops working:
(xt/q (xt/db node)
      '{:find [name funds stock item]
        :where [[e :company-name name]
                [e :credits funds]
                [e #_"THIS IS THE ONLY CHANGE ->" item stock]] 
        :in [[e item]]}
      [:tombaugh-resources :units/CH4])
;; => Execution error (IllegalArgumentException) at xtdb.error/illegal-arg (error.clj:12).
;;    Query didn't match expected structure
Could anyone explain to me why this doesn't work? Thank you!

Dallas Surewood05:10:37

It looks like you misunderstand the query structure a little

(xt/q (xt/db node)
      '{:find [name funds stock item]
        :where [[e :company-name name]
                [e :credits funds]
                [e item stock]]
        :in [[e item]]}
      [:tombaugh-resources :units/CH4])
You say you are using the "item" parameter, but that is not what this query does. You seem to think that :in is doing some kind of binding where it puts :units/CHR into the item symbol. That is not what's happening here. The format for a where block is [<row_symbol> <access_key> <name_to_bind_to>]. You will pretty much always have e at the beginning of each row unless you're doing something complicated. But you're supposed to pick the document field you want to bind next and assign it to a symbol. So for example, [e :item stock] would put the :item field of the document into the stock symbol. You have provided a symbol, which is invalid. It doesn't know how to access the document with that. It looks like you've gone off the tutorial a little. Notice that the only example of using item like you are is doing something different
(defn stock-check
  [company-id item]
  {:result (xt/q (xt/db node)
                 {:find '[name funds stock]
                  :where ['[e :company-name name]
                          '[e :credits funds]
                          ['e item 'stock]]
                  :in '[e]}
                 company-id)
   :item item})
This is manually quoting everything that isn't item so that it can evaluate the item into a keyword argument that we pass in. So we call (stock-check 1 :units/Au)and that means stock becomes whatever the value of :units/Au is in each document.

🙏 1
refset11:10:00

Hey, yep, XT doesn't support parameterised attributes - you need to quote them in (so they're technically different queries)

Olav Fosse14:10:22

Hey, thanks for the explanation! My thinking was based on this section of the docs: https://v1-docs.xtdb.com/language-reference/1.24.1/datalog-queries/#_tuple_binding If I understand correctly, you can parameterise with an :in clause, such that the parameters can be used as an entity or value in a :where tuple or as a :find value, but not as the attribute in a :where tuple. Is that right? In which case, why can't I use an :in parameter as an attribute in the :where tuple? I'll read the rest of the tutorial tomorrow so maybe I get it on my own 🤓

Dallas Surewood14:10:17

No it's actually the opposite. :where is doing double duty. It's both filtering documents and binding them to names.

Dallas Surewood14:10:45

All :in does is let you pass in parameters. But you need to have already bound the names with :where.

Dallas Surewood14:10:22

"Ivan" is matched to first-name, but first-name is mapped to :name from the where clause

Dallas Surewood14:10:34

When I say :where is filtering documents, I mean it's making sure the :name key is present in the document. Then it binds it to first-name. It is NOT doing any work with "Ivan", that's what :in is for

refset15:10:35

> why can't I use an :in parameter as an attribute in the :where tuple? for the same reason you can't use any other logic var in the attribute position of a :where tuple - the engine simply doesn't support it

👍 1
Olav Fosse15:10:20

Alright, I get it now 😄 My mistake was in assuming it was possible to use logic vars in the attribute position of a :where tuple like in datomic. I just had to unlearn that assumption 🤓 Thank you so much for the help :^)

🙏 1