asami

2022-10-08T13:12:40.322789Z

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 😊

quoll 2022-10-08T13:30:38.549599Z

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

2022-10-08T13:46:22.820899Z

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

quoll 2022-10-08T13:47:29.503799Z

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

2022-10-08T13:47:32.476799Z

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?

2022-10-08T13:47:41.137349Z

No rush!

quoll 2022-10-08T13:50:28.831229Z

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

quoll 2022-10-08T13:52:04.351159Z

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

quoll 2022-10-08T13:52:53.654159Z

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

quoll 2022-10-08T13:53:32.715679Z

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

quoll 2022-10-08T13:56:16.141029Z

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

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

quoll 2022-10-08T13:57:37.415479Z

Except that also screws with ?m and ?text

2022-10-08T13:59:11.577889Z

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

quoll 2022-10-08T13:59:48.627249Z

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

quoll 2022-10-08T14:01:47.486519Z

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

quoll 2022-10-08T14:02:16.443769Z

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

2022-10-08T15:19:42.069389Z

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. 🙂

2022-10-08T15:20:26.690389Z

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

quoll 2022-10-08T16:23:24.663229Z

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

quoll 2022-10-08T16:25:31.198269Z

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

quoll 2022-10-08T16:25:50.197929Z

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

quoll 2022-10-08T16:26:37.537369Z

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)