以编程方式生成Datomic查询

MRo*_*lin 1 macros clojure datomic

应用

我想以编程方式生成以下形式的查询.

(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))
Run Code Online (Sandbox Code Playgroud)

这些是用于收集预定义属性集的相当标准的查询.

现行解决方案

我能做的最好的就是使用:in如下

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

但这给了我n每个实体的一系列事实.我真的希望收到一组长度向量,n+1其中n是指定属性的数量.我还希望元素的顺序能够反映属性的顺序.

程序化生成

因为Datomic查询是数据结构,所以我应该能够以编程方式生成它们.我发现这很困难有几个原因,这两个原因都源于我对宏的不熟悉

  1. 我怎样才能创建像这样的术语?val1.我可以映射?到一堆生成的字符串吗?

    (map ? value-strings)

  2. 领导'吓到了我.这不会阻止我的自动代码运行,直到?x处理完元素之后?

或者,是否有更惯用的解决方案?

Joh*_*hnJ 6

更新 ......

正如@TomJack所写,Datomic支持基于地图的替代语法,这将使您的查询更容易.

(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)))
Run Code Online (Sandbox Code Playgroud)