Fork me on GitHub
#asami
<
2022-10-08
>
Mattias13:10:40

Ok, another fantastically basic question - I need help with using parameters/external data/inputs in queries. This is either from 1) not knowing Datomic or Datalog at all, or I’m just very very slow. Anyway… some examples needed. There is one example of adding #“somestring” at the end of a query, but how that works eludes me. All pointers appreciated 😊

quoll13:10:38

I think I follow the question. Can you give a specific example though, please?

Mattias13:10:22

Thank you! So, this example does not do what I naively wanted:

(let [blah "01"]
        (d/q '[:find ?text :where [?m :text ?text][?m :code blah]] @asami-conn))

quoll13:10:29

I’ll be back at my keyboard in 2 minutes…

Mattias13:10:32

So… in another world (SQL) it would be something like a prepared statement with parameters and stuff. But here I’m guessing something like appending parameters at the end and they get bound to… things?

quoll13:10:28

The thing about SQL is that it's usually based on a string

quoll13:10:04

So you can either modify the string, to include some variable from the local context, or you prepare a query, and then pass the variables along args, similarly to how you might with clojure.core/format

quoll13:10:53

I could try the latter, but it seems redundant when Asami (and Datomic) don't use query strings. We use query structures

quoll13:10:32

The first approach that some people use in the above is to unquote the symbol into place

quoll13:10:16

Avoiding the query call for a moment, you can use:

(let [blah "01"]
  `[:find ?text :where [?m :text ?text][?m :code ~blah]])

quoll13:10:37

Except that also screws with ?m and ?text

Mattias13:10:11

Is there an idiomatic way, or am I approaching this all wrong? 🙂

quoll13:10:48

I usually build the query a little more manually. In this case, the query is a vector so you can just conj the last constraint on:

(conj '[:find ?text :where [?m :text ?text]] ['?m :code blah])

quoll14:10:47

but when I'm building a query like that, then I'll usually use the map form instead:

{:find '[?text]
 :where (conj ['[?m :text ?text]] ['?m :code blah])}

quoll14:10:16

(sorry for going back to edit some of these. I had a late night and I only just got up) 🙂

Mattias15:10:42

No worries, thanks so much for taking the time. If I want to study this more, why is it that my initial attempt doesn’t work? Anything I can read up on regarding the execution order or something? I’m missing the forest for the trees, I think. 🙂

Mattias15:10:26

And thanks for the examples, that helps me understand what you mean by query structures. I’m getting there, slowly 😋

quoll16:10:24

execution order is actually calculated, unless you explicitly ask it not to. That's done by adding, :planner :user to the end of the query arguments

quoll16:10:31

Otherwise, it tries to figure out which are the smallest patterns to resolve, and it sorts the execution order from smallest to largest

quoll16:10:50

(which you should be doing if you're querying Datomic)

quoll16:10:37

This is because Datomic does NOT plan queries. It executes them in the order you request (just like if you used :planner :user at the end of your query parameters)