Datomic中如何实现带参数化:where子句的查询?
解决Datomic自定义where子句的entities-where函数问题
原可运行查询函数
(defn entities [entity-map] (db/q '[:find [(pull ?e pattern) ...] :in $ pattern ?primary-field :where [?e ?primary-field]] (:pattern entity-map) (:primary entity-map)))
需求与尝试
需要实现支持自定义where子句的entities-where函数,以下是两种失败的尝试:
第一种尝试写法
(defn entities-where [entity-map & where-clauses] (db/q '[:find [(pull ?e pattern) ...] :in $ pattern ?primary-field [?where ...] :where [?e ?primary-field] ?where] (:pattern entity-map) (:primary entity-map) where-clauses))
第二种尝试写法及调用示例
(defn entities-where [entity-map where-clause] (db/q '[:find [(pull ?e pattern) ...] :in $ pattern ?primary-field where+ :where [?e ?primary-field] where+] (:pattern entity-map) (:primary entity-map) where-clause)) (entities-where my-entity-map '[?e :touch/time 1720546420839])
该写法报错:Don't know how to create ISeq from: clojure.lang.Symbol
示例实体映射:
{:primary :lead/id :pattern '[*, {:lead/status [*]}]}
问题解决
Datomic的where+语法要求传入子句序列而非单个子句,同时原函数和尝试写法都遗漏了关键的数据库连接参数$,这是核心问题。以下是两种可行方案:
方案1:支持单个/多个where子句(可变参数)
(defn entities-where [entity-map & where-clauses] (db/q '[:find [(pull ?e pattern) ...] :in $ pattern ?primary-field [?where ...] :where [?e ?primary-field] (list ?where)] (:db entity-map) (:pattern entity-map) (:primary entity-map) where-clauses))
调用示例:
; 单个子句 (entities-where my-entity-map '[?e :touch/time 1720546420839]) ; 多个子句 (entities-where my-entity-map '[?e :touch/time 1720546420839] '[?e :lead/status :active])
方案2:明确接受子句序列(where+语法)
(defn entities-where [entity-map where-clauses] (db/q '[:find [(pull ?e pattern) ...] :in $ pattern ?primary-field where+ :where [?e ?primary-field] where+] (:db entity-map) (:pattern entity-map) (:primary entity-map) where-clauses))
调用时需传入子句序列(单个子句也要用括号包裹):
(entities-where my-entity-map '([?e :touch/time 1720546420839]))
关键注意点
- 必须传入db连接:
db/q的第一个参数$对应数据库连接,需从entity-map中取出:db字段传入,否则查询无法执行。 - where子句格式匹配:
- 使用
[?where ...]时,直接传入可变参数集合即可; - 使用
where+时,必须传入子句的序列(如包含向量的列表),不能传单个向量。
- 使用
内容的提问来源于stack exchange,提问作者Scott Klarenbach
相关产品推荐
相关产品推荐

