2013-09-28 16 views
13

Interesują mnie encje i ich sygnatury czasowe. Zasadniczo chcę uporządkować listę podmiotów na podstawie czasu.Pobierz najnowszą jednostkę z Datomic

W tym celu mam składa następujące funkcje:

(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))) 

Który czuję musi być hack zakorzenione w nieświadomości.

Czy ktoś bardziej zorientowany w idiomatycznym geniuszu Datomic i uaktualni moje paradygmaty?

Odpowiedz

7

byłem dręczony przez ideę dodanie dodatkowych znaczników czasu do bazy danych, która nominalnie rozumie czas jako zasady pierwszej klasy i SO (po nocy rozmyślałem nad podejściami przedstawionymi przez Ulrik Sandberg) rozwinął następującą funkcję:

(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)))) 

To idiomatyczne w Datalogu pominąć wiązanie do samego ID transakcji jak zwykle nie obchodzi. W tej sytuacji bardzo zależy nam na słowach Augusta Lileaasa, chcemy "przejść przez transakcję" (są sytuacje, w których chcielibyśmy czas utworzenia postu, ale dla tej aplikacji czas transakcji wystarczy dla podmiotów zamawiających).

Godnym uwagi minusem tego podejścia jest to, że ostatnio edytowane wpisy zostaną podskoczone na liście. W tym celu będę musiał zrobić coś później, aby uzyskać ich "pierwsze pojawienie się" w Datomic dla historii postów na blogu.

Podsumowując: Połączyłem identyfikator podmiotu transakcji z identyfikatorem jednostki "post", a następnie sprawdziłem znacznik czasu transakcji za pomocą tej funkcji do późniejszego sortowania.

+2

Warto zauważyć, że AFAIK, to daje natychmiastowy moment, w którym aktualna wartość: post/title została potwierdzona dla podmiotu, a nie kiedy podmiot był ostatnim przedmiotem transakcji. – spieden

2

Nie ma na to bardziej eleganckiego sposobu niż przechodzenie transakcji. Właśnie dlatego wolę mieć oddzielny atrybut specyficzny dla domeny dla znaczników czasu, zamiast polegać na znacznikach czasu transakcji z Datomic. Jednym z przykładów, gdzie jest to konieczne, jest scalenie: załóżmy, że masz wiki i chcesz połączyć dwie strony wiki. W takim przypadku prawdopodobnie chcesz kontrolować sygnaturę czasową i nie używaj znacznika czasu z transakcji.

Lubię mieć atrybuty :created-at i :changed-at. Kiedy transakcji nowe podmioty:

[[: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.)]] 

Następnie aktualizacje:

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

ten sposób wszystko, co mam zrobić, to odczytać: stworzony-at atrybutem podmiotu, który będzie gotowy i czekanie w indeksie.

(defmacro find-one-entity 
    "Returns entity when query matches, otherwise nil" 
    [q db & args] 
    `(when-let [eid# (ffirst (d/q ~q ~db [email protected]))] 
    (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"))