Reputation: 57251
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.
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.
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
How can I create terms like ?val1
. Can I map ?
onto a bunch of generated strings?
(map ? value-strings)
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?
Upvotes: 1
Views: 563
Reputation: 4823
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)))
Upvotes: 6