microrm 0.6.3

Lightweight ORM using sqlite as a backend
Documentation
use microrm::prelude::*;
use test_log::test;

mod common;

#[derive(Entity)]
struct KV {
    key: usize,
    value: usize,
}

#[derive(Schema)]
struct KVStore {
    kvs: microrm::IDMap<KV>,
}

#[test]
#[should_panic]
fn txn_should_abort() {
    let (pool, db): (_, KVStore) = common::open_test_db!();
    // open two transactions
    let mut txn1 = pool.start().unwrap();
    let mut txn2 = pool.start().unwrap();

    db.kvs.insert(&mut txn2, KV { key: 0, value: 0 }).unwrap();

    // now insert different data via txn1 --- this should fail
    let _err = db.kvs.insert(&mut txn1, KV { key: 0, value: 1 });

    unreachable!()
}

#[test]
fn txn_read_old_data_rollback() {
    let (pool, db): (_, KVStore) = common::open_test_db!();

    let mut itxn = pool.start().unwrap();

    let mut k0 = db
        .kvs
        .insert_and_return(&mut itxn, KV { key: 0, value: 0 })
        .unwrap();

    itxn.commit().unwrap();

    let mut txn1 = pool.start().unwrap();
    let mut txn2 = pool.start().unwrap();

    // use second transaction to overwrite old value
    k0.value = 1;
    k0.sync(&mut txn2).unwrap();

    // this should produce old data when we read k0 again
    let nk0 = db.kvs.by_id(&mut txn1, k0.id()).unwrap().unwrap();
    assert_eq!(nk0.value, 0);

    let Err(microrm::Error::TransactionAbort) = txn2.commit() else {
        panic!("Transaction was successful when it should not have been");
    };
}

#[test]
fn txn_read_old_data_wal() {
    let (pool, db): (_, KVStore) = microrm::ConnectionPool::open(
        microrm::db::ConnectionPoolConfig::new(common::test_db_path("txn_read_old_data_wal"))
            .with_wal(),
    )
    .unwrap();

    let mut itxn = pool.start().unwrap();

    let mut k0 = db
        .kvs
        .insert_and_return(&mut itxn, KV { key: 0, value: 0 })
        .unwrap();

    itxn.commit().unwrap();

    let mut txn1 = pool.start().unwrap();
    let mut txn2 = pool.start().unwrap();

    // use second transaction to overwrite old value
    k0.value = 1;
    k0.sync(&mut txn2).unwrap();

    // this should produce old data when we read k0 again
    let nk0 = db.kvs.by_id(&mut txn1, k0.id()).unwrap().unwrap();
    assert_eq!(nk0.value, 0);

    txn2.commit().unwrap();

    // this should still produce the old data
    let nk0 = db.kvs.by_id(&mut txn1, k0.id()).unwrap().unwrap();
    assert_eq!(nk0.value, 0);

    // but a new transaction should give the new data
    let mut txn1 = pool.start().unwrap();
    let nk0 = db.kvs.by_id(&mut txn1, k0.id()).unwrap().unwrap();
    assert_eq!(nk0.value, 1);
}