vvvvalvalval / datomock

Mocking and forking Datomic Peer connections in-memory.
MIT License
130 stars 6 forks source link

Fork at a given T point (yes, it's possible) ; no it's not #9

Closed mszajna closed 1 year ago

mszajna commented 1 year ago

First of all, thanks for Datomock, this is super useful for testing! The one thing that's been bugging me was the inability to fork at arbitrary T point.

I'm aware that d/as-of does not allow subsequent speculative transactions. However, I've been able to develop a variant of as-of that does https://www.reddit.com/r/Clojure/comments/yemxzi/datomic_with_asof_or_the_elusive_branching_off_a/. I've been using it for local dev for a couple of weeks now and it seems to work well enough.

Do you think you'd be interested in incorporating it into your library? I'm thinking fork-conn taking T as an optional arg. This would be very valuable for debugging production issues, or writing reproducible tests. I considered publishing my as-of'' in a library of my own, but as you can see, the solution is too simple to warrant a separate dependency. If you think you'd want this kind of feature here though, I'd be happy to produce a PR.

Some considerations:

On the reddit thread someone brought up performance as a potential issue. It's true that d/filter has a significantly higher cost than d/as-of, and that cost stacks while d/as-of does not. Having said that, for the purposes of datomock, you'd only really want to branch off once, which has negligible cost. I've been experimenting with using primitive arithmetic but that didn't help much. The only thing that seems to make a difference is using (.tx datom) instead of destructuring (compared to the code in reddit post).

It's important to note that the resulting DB d/is-filtered will be true. The only way to work around it I can think of is to (reify Database ..) which is extra overhead. I don't mind much either way, let me know what you think.

The other difference from regular connections is that the T values are not continuous. This means, the next speculative transaction won't be T+1. It will be (d/next-t (d/db original-connection)). I don't recon this would ever be an issue for anyone, but it's only fair to point out.

mszajna commented 1 year ago

I retract this. Looks like unfortunately d/with is inconsistent in whether the transaction is applied to the filtered or unfiltered view. In particular, on datomic 1.0.6202, transaction functions have been observed to see the filtered view as expected, but simple assertions and retractions are recorded against unfiltered DB.