replikativ / datahike

A fast, immutable, distributed & compositional Datalog engine for everyone.
https://datahike.io
Eclipse Public License 1.0
1.63k stars 97 forks source link

[Bug]: as-of does not include time-point and since does not exlude time-point #712

Closed jonasseglare closed 2 months ago

jonasseglare commented 2 months ago

What version of Datahike are you using?

0.6.1586

What version of Java are you using?

openjdk 21.0.4 2024-07-16 LTS

What operating system are you using?

Mac OS X

What database EDN configuration are you using?

Doesn't matter.

Describe the bug

I assume that the functions as-of and since should work just like they work in Datomic? From the Datomic docs, it says

For as-of:

An as-of filter returns a database "as of" at a particular point in time, ignoring any transactions after that point.

For since:

A since filter is the opposite of as-of. Taking the same point-in-time arguments as as-of, since returns a value of the database that includes only datoms added by transactions after that point in time.

From the above, I read that as-of will include the time point, whereas since will exclude the time point.

But this is not how it is implemented in Datahike, in case time-point is a Date. I believe this is a mistake:

(defn- as-of-pred [time-point]
  (if (date? time-point)
    (fn [^Datom d] (.before ^Date (.-v d) ^Date time-point))
    (fn [^Datom d] (<= (dd/datom-tx d) time-point))))

(defn- since-pred [time-point]
  (if (date? time-point)
    (fn [^Datom d] (.after ^Date (.-v d) ^Date time-point))
    (fn [^Datom d] (>= (.-tx d) time-point))))

What is the expected behaviour?

That as-of will include the time point and since will exclude it.

How can the behaviour be reproduced?

On my Macbook, I discovered a unit test that uses as-of. It only fails sometimes, namely when the time-point is the same as the timestamp of the last transaction. Then I get this error:

ERROR in datahike.test.time-variance-test/test-as-of-db (utils.cljc:142)
get values at specific time
Exception: clojure.lang.ExceptionInfo: Nothing found for entity id [:name "Alice"]
{:error :entity-id/missing, :entity-id [:name "Alice"]}