So, based on your source-code, I have managed to simplify the code a bit:
(defn add-entity-ns
[ekey datom-map]
(reduce-kv (fn [a k v]
(assoc a (keyword
(name ekey)
(name k))
v))
{}
datom-map))
(defn retrieve-entity
[conn constraint-map]
(let [name-fn (comp symbol
(partial str "?")
name)
param-names (map name-fn
(keys constraint-map))
param-vals (vals constraint-map)
constraint-map (add-entity-ns :posts constraint-map)
where-clause (map #(vector '?e % %2)
(keys constraint-map)
param-names)
in-clause (conj param-names '$)
final-clause (concat [:find '?e]
[:in] in-clause
[:where] where-clause)]
(apply d/q final-clause (d/db conn) param-vals)))
A note: When I started using datomic, I wrote myself similar functions to generate queries. I ended up throwing them away, for several reasons:
- It's a mess. The Datalog is designed for doing logic queries. It takes significantly longer to generate a logic query and invoke it, even though datomic does caching. This is because Datalog has to resolve the query logically, which takes quite some time.
- If you know how to query, it performs much better to actually query once for all entities and then filter them out, doing usual sequence transformation (and for a huge database, use reducers!). This performs on avg. 20x faster than Datalog (benchmarked using criterium).
If you don't believe me, write a query that queries all your :post/x entities from the database, than filter out what posts match your criteria using
filter
and so on. If you have a large database, use reducers withfoldcat
. - I wrote myself a filtering engine (for bunches of entities) that serves as sort of a query-DSL. I modify it depending on the project and database structure. Being able to write DSLs is the power of LISP and Datomic makes it really possible thanks to entities being hash-map like data-structures. It performs way faster than Datalog (at the cost of being domain-specific).