##// END OF EJS Templates
Fix transactions for objects fetched from the db (not created in this image)
Fix transactions for objects fetched from the db (not created in this image)

File last commit:

r1:4df1cd4a default
r5:94e6ef46 tip default
Show More
README.md
71 lines | 3.6 KiB | text/x-minidsrc | MarkdownLexer
Initial commit
r0
# mito-transactions
A set of MOP magic adding several features to [mito](https://github.com/fukamachi/mito).
* Transactions with rollback and commit operating on both Lisp image and SQL db
* "Caching" objects so they keep their identity on subsequent fetches
## Rationale
I needed a good object database for Common Lisp. [bknr.datastore](https://github.com/hanshuebner/bknr-datastore) and [mito](https://github.com/fukamachi/mito) immediately became the first candidates but I've met troubles with both.
Mito doesn't really behave like an object database, the most obvious sign of it is different identity for the same object (the same row) fetched from the DB. Also it doesn't support transactions and requires specifying column types for each slot but there's nothing to do about the latter in an ORM.
bknr.datastore is a prevalence database and there's always a risk that your data will grow faster than RAM. Also I've lost data during development more than once and its migration protocol is somewhat convoluted. But the biggest problem is that Common Lisp is currently the only language that can read bknr.datastore format.
So, the obvious thing to do is to take a library that gets more things right and implement the missing ones.
## Cache
Just load `mito-transactions` system and use/import/local-nickname `mito-transactions` package instead of `mito`.
Whenever an object is fetched from the database using any means (`find-dao`, `retrieve-dao`, `select-dao`, `select-by-sql`) the object will be checked against the cache and if an object with the same id is already present its slots would be updated with the new data from the db. Otherwise the object is placed in the cache. Objects are only flushed when they are GC'ed or deleted from the DB (using `delete-dao` or `delete-by-values`)
```cl
(make-instance 'person :name "someseven")
;=> #<PERSON 54 {10057EB383}>
Correct README
r1 (find-dao 'person 'name "someseven")
Initial commit
r0 ;=> #<PERSON 54 {10057EB383}>
```
They'll have the same identity unless GC runs between the two calls.
There are only two new functions:
##### GET-DAO *CLASS* *ID*
Retrieves an object by ID by first checking the cache and only accessing database if the object is not in the cache.
##### GET-DAO-ONLY-FROM-CACHE *CLASS* *ID*
Same, but never accesses the database. If the object is not cached it returns nil. Mostly useful for testing.
## Transactions
The transaction system tries to keep in-image objects and database rows in sync. Ideally they should only be out-of-sync during a transaction. When a transaction is committed all changed objects are synced to the database. When a transaction is rolled back all objects get their pre-transaction slot values back. `make-instance` automatically puts the object in both the database and the cache. You don't have to ever use `mito:save-dao`, `mito:insert-dao`, or `mito:update-dao`. Modifying non-ghost slots outside of a transaction is forbidden.
```cl
Correct README
r1 (let ((person (make-person)))
Initial commit
r0 (with-transaction ()
(incf (age person))
(if (check-something person)
(commit)
(rollback)))
(setf (name person) "foo")) ; ERROR
```
Correct README
r1 Transactions are also committed on normal exit and rolled back on non-local exit.
Initial commit
r0
##### WITH-TRANSACTION () &BODY *BODY*
Runs the body inside a transaction. Nested transactions are allowed but internal ones can't call `commit` and will rollback all nested transactions on `rollback`.
##### COMMIT and ROLLBACK
Correct README
r1 Functions to commit or rollback a transaction. Defined locally inside `with-transaction` body. Either call terminates the transaction without evaluating its remainder.
Initial commit
r0
## License
Licensed under the LLGPL License.