Question

Application

I'd like to programattically generate queries of the following form.

(q '[:find ?id ?val1 ?val2 ?val3 ?val4 ...
     :where [?x :id ?id] 
            [?x :attr1 ?val1]
            [?x :attr2 ?val2]
            [?x :attr3 ?val3]
            [?x :attr4 ?val4]
            ....]
     (db conn))

These are fairly standard queries to collect a predefined set of attributes.

Current Solution

The best I can do is to use :in as follows

(q '[:find ?id ?val
     :in  $ [?attr ...]
     :where [?x :id ?id] 
            [?x ?attr ?val]]
     (db conn) [:attr1 :attr2 :attr3 :attr4])

But this gives me a set of n facts for each entity. Really I want to receive a set of vectors of length n+1 where n is the number of specified attributes. I also want the order of elements to reflect the order of the attributes as they are given.

Programmatic Generation

Because Datomic queries are data structures I should be able to programmatically generate them. I find this difficult for a couple reasons, both of which stem from my unfamiliarity with macros

  1. How can I create terms like ?val1. Can I map ? onto a bunch of generated strings?

    (map ? value-strings)

  2. The leading ' scares me. Doesn't this stop my automated code from running until after elements like ?x are dealt with?

Or, is there a more idiomatic solution?

Was it helpful?

Solution

Update...

as @TomJack writes, Datomic supports an alternate map-based syntax which will make your query easier.

(let [attributes [:name :height :weight :age]
      valnames (map #(symbol (str "?" (name %))) attributes)
      x-terms (map #(vector '?x %1 %2) attributes valnames)
      query {:find valnames
             :where (cons ['?x :id '?id] x-terms)}]
  (q query (db conn)))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top