15

I'm interested in entities and their timestamps. Essentially, I want a time-sorted list of entities.

To that end, I've composed the following functions:

(defn return-posts
  "grabs all posts from Datomic"
  []
  (d/q '[:find ?title ?body ?slug
         :where
         [?e :post/title ?title]
         [?e :post/slug ?slug]
         [?e :post/body ?body]] (d/db connection)))

(defn get-postid-from-slug
  [slug]
  (d/q '[:find ?e
         :in $ ?slug
         :where [?e :post/slug ?slug]] (d/db connection) slug))

(defn get-post-timestamp
  "given an entid, returns the most recent timestamp"
  [entid]
  (->
   (d/q '[:find ?ts
          :in $ ?e
          :where
          [?e _ _ _]
          [?e :db/txInstant ?ts]] (d/db connection) entid)
   (sort)
   (reverse)
   (first)))

Which I feel must be a hack rooted in ignorance.

Would someone more well-versed in idiomatic Datomic usage chime in and upgrade my paradigms?

4

2 回答 2

9

我对将额外的时间戳添加到名义上将时间理解为一流原则的数据库的想法感到困扰,因此(经过一夜对Ulrik Sandberg概述的方法的思考之后)发展了以下功能:

(defn return-posts
  "grabs all posts from Datomic"
  [uri]
  (d/q '[:find ?title ?body ?slug ?ts
         :where
         [?e :post/title ?title ?tx]
         [?e :post/slug ?slug]
         [?e :post/body ?body]
         [?tx :db/txInstant ?ts]] (d/db (d/connect uri))))

在 Datalog 中,省略与事务 ID 本身的绑定是惯用的,因为我们通常不关心。在这种情况下,我们非常关心并且用 August Lileaas 的话来说,希望“遍历事务”(在某些情况下,我们希望创建帖子的时间,但对于这个应用程序来说,事务时间对于订购实体来说已经足够了)。

这种方法的一个显着缺点是最近编辑的条目将在列表中增加。为此,我稍后将不得不做一些事情,以便让它们在 Datomic 中“首次出现”以获取博客标准的帖子历史记录。

总结一下:我已经为每个“post”实体ID绑定了事务实体ID,然后用这个函数查找事务时间戳以供以后排序。

于 2013-09-29T17:47:29.877 回答
2

没有比遍历事务更优雅的方法了。这就是为什么我更喜欢为时间戳设置一个单独的域特定属性,而不是依赖于 Datomic 的事务时间戳。一个必要的示例是合并:假设您有一个 wiki,并且您想要合并两个 wiki 页面。在这种情况下,您可能希望自己控制时间戳,而不是使用事务中的时间戳。

我喜欢有属性:created-at:changed-at。当我交易新实体时:

[[:db/add tempid :post/slug "..."]
 [:db/add tempid :post/title "A title"]
 [:db/add tempid :created-at (java.util.Date.)]
 [:db/add tempid :changed-at (java.util.Date.)]]

然后进行更新:

[[:db/add post-eid :post/title "An updated title"]
 [:db/add post-eid :changed-at (java.util.Date.)]]

这样我所要做的就是读出实体的 :created-at 属性,该属性将准备好并在索引中等待。

(defmacro find-one-entity
  "Returns entity when query matches, otherwise nil"
  [q db & args]
  `(when-let [eid# (ffirst (d/q ~q ~db ~@args))]
     (d/entity ~db eid#)))

(defn find-post-by-slug
  [db slug]
  (find-one-entity
    '[:find ?e
      :in $ ?slug
      :where
      [?e :post/slug ?slug]]
    db
    slug))

;; Get timestamp
(:created-at (find-post-by-slug db "my-post-slug"))
于 2013-09-28T21:41:11.877 回答