use emdb::{Emdb, Error};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let db = Emdb::open_in_memory();
db.insert("account:alice", "100")?;
db.insert("account:bob", "50")?;
println!("opening balances: alice=100, bob=50");
db.transaction(|tx| {
tx.insert("account:alice", "70")?;
tx.insert("account:bob", "80")?;
Ok(())
})?;
println!(
"after commit: alice={}, bob={}",
String::from_utf8_lossy(&db.get("account:alice")?.unwrap_or_default()),
String::from_utf8_lossy(&db.get("account:bob")?.unwrap_or_default()),
);
assert_eq!(db.get("account:alice")?.as_deref(), Some(b"70".as_slice()));
assert_eq!(db.get("account:bob")?.as_deref(), Some(b"80".as_slice()));
let result: Result<(), Error> = db.transaction(|tx| {
tx.insert("account:alice", "0")?;
tx.insert("account:bob", "999")?;
Err(Error::InvalidConfig("balance reconciliation failed"))
});
assert!(result.is_err(), "transaction should have rolled back");
println!("\nrolled back. balances unchanged:");
println!(
" alice={}, bob={}",
String::from_utf8_lossy(&db.get("account:alice")?.unwrap_or_default()),
String::from_utf8_lossy(&db.get("account:bob")?.unwrap_or_default()),
);
assert_eq!(db.get("account:alice")?.as_deref(), Some(b"70".as_slice()));
assert_eq!(db.get("account:bob")?.as_deref(), Some(b"80".as_slice()));
let total: u64 = db.transaction(|tx| {
let alice = String::from_utf8_lossy(&tx.get("account:alice")?.unwrap_or_default())
.parse::<u64>()
.unwrap_or(0);
let bob = String::from_utf8_lossy(&tx.get("account:bob")?.unwrap_or_default())
.parse::<u64>()
.unwrap_or(0);
Ok(alice + bob)
})?;
println!("\nlive total balance = {total}");
assert_eq!(total, 150);
Ok(())
}