Hello all! Can you help me to clarify something? Is there any way for isolated behaviour out of the box? Like: 1. get immutable database from connection 2. make queries on it 3. make transactions to it 4. make queries regarding transactions from p.3 5. ....many other query/transaction operations... 6. persist changes to storage or completely forget them
If datahike works enough like datomic - on prem: Not out of the box - you will need to be able to convert all the "local transaction history" into one or many transactions that you can persist. This video (from 2015) is https://docs.datomic.com/resources/videos.html#reified-transactions suggest another way to work with multi transactions, called sagas. I find it quite demanding to model the data to allow for sagas as outlined, but if you find a way to do it - it is very powerful.
But I have implemented logic as you outline it as well. In short - keep the transaction log and collapse it and keep track on which new entities are created locally and their tempid -> eid. Like a git squash but for transactions. When you collapse the transaction - make sure to keep track of the ids (datoms added and then removed will never show up in the transaction log if you squash transactions first adding and then removing entities. Usually you will want to make some guarantees on that the actual database hasn't changed under your feet. Decide which datoms that should be transacted as CAS - and from what DB-version you can make such CAS:es without breaking your domain model constraints. I hope this is of any help
Thank you. Yes, for now I am doing it manually almost as you said. Actually I need something like datalevin's with-transaction macro. It could be perfect if it would work in asynchronous setup, but unfortunately it doesnβt. That why I am looking for alternatives..
Hmm, in datomic that with-transaction behaviour could mostly be solved using transaction functions. In DataScript there's a possibility to call functions during transaction (IIRC), I'm not sure how datahike handles function calls during transaction time, or if it is possible to specify functions that should be run during (precious) transaction time.
Oh, I found something: https://github.com/replikativ/datahike/blob/main/src/datahike/db/transaction.cljc#L629
You can, just like in DataScript, use :db.fn/call to call a function during transaction time. This should be kept quick, but it is possible!
So... do you mean to call (transact! conn [[:db.fn/call f args...]]) where f is the almost whole my application logic function?
Will it work this way?
Well, actually I think it will work (but you have to return the correct data for the system - I think it needs to return transaction data which will be transacted as part of the transaction). I don't recommend it though - you put a big lock on you database transactions while doing it.
Yes, that is what I am concerned about
There are some different ways to make sure you have a consistent data model.
Use squashing + selective CAS statements (+ retries!) if you think that is necessary to keep the system efficient but correct.
If there is no performance problems for the transaction logic you can run the whole transaction in a :db.fn/call-block.
If you have a single JVM-instance you can easily keep some separate data structure along with the database to help with consistency if you think that will make transactions quicker - but it must of course be correctly updated as well...
Ok. Thank you for your suggestions
I think this is what you might want @sasha_bogdanov_dev.
https://github.com/replikativ/datahike/blob/main/doc/versioning.md
I don't know why Datomic did not do this, it always seemed weird to me that you can only add transactions in memory but don't provide a git-like workflow.
With this model you don't need to be able to keep everything in memory, you literally work on a branch and then merge back. Maybe this is too complicated, I am happy to get feedback for the API. It is still experimental, but I would like to change this soon.
Btw. are you by chance related to https://en.wikipedia.org/wiki/Alexander_Bogdanov ?
Okay. Thank you! I will check it and return with feedback. No, he is not my ancestor) btw wiki said that itβs not his real family name
And one more question: what is lifecycle of :mem database? Have I use different :id for each test? Will it take memory until.. reboot? JVM stop? Or better manually clear it always?
You have to disconnect and delete the database and it should be garbage collected. Yes, you need a different id for each database and if you run your tests in parallel it would be good to use different ids for each test.
Basically the standard workflow you have also for durable databases, just that you need to hold it in memory while you use it.
For REPL development you might not care about cleaning it up, but it is always good to do.