datahike

2024-10-27T11:30:44.752129Z

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

Linus Ericsson 2024-10-27T12:01:14.928739Z

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.

πŸ‘€ 1
Linus Ericsson 2024-10-27T12:08:48.361299Z

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

2024-10-27T12:14:36.936079Z

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..

Linus Ericsson 2024-10-27T12:23:33.656629Z

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.

Linus Ericsson 2024-10-27T12:32:59.178719Z

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!

πŸ‘ 1
2024-10-27T12:36:33.189929Z

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?

Linus Ericsson 2024-10-27T12:39:34.386259Z

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.

2024-10-27T12:40:16.399139Z

Yes, that is what I am concerned about

Linus Ericsson 2024-10-27T12:52:02.581679Z

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...

2024-10-27T12:55:26.707079Z

Ok. Thank you for your suggestions

whilo 2024-10-28T06:16:38.175269Z

I think this is what you might want @sasha_bogdanov_dev.

whilo 2024-10-28T06:20:13.318899Z

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.

whilo 2024-10-28T06:21:17.213039Z

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.

whilo 2024-10-28T06:22:01.938319Z

Btw. are you by chance related to https://en.wikipedia.org/wiki/Alexander_Bogdanov ?

2024-10-28T08:04:11.311629Z

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

πŸ‘ 1
2024-10-27T13:27:20.100859Z

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?

whilo 2024-10-28T18:38:08.828499Z

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.

πŸ‘ 1
whilo 2024-10-28T18:38:36.121929Z

Basically the standard workflow you have also for durable databases, just that you need to hold it in memory while you use it.

whilo 2024-10-28T18:39:00.028419Z

For REPL development you might not care about cleaning it up, but it is always good to do.

πŸ‘ 1