persy 1.5.0

Transactional Persistence Engine
Documentation
mod helpers;
use helpers::create_and_drop;
use persy::{ByteVec, IndexIter, IndexType, TxIndexIter, ValueMode, PE};
use persy::{Persy, PersyError};

fn create_and_drop_index<F>(test: &str, f: F)
where
    F: FnOnce(&Persy, &str),
{
    create_and_drop_index_mode(test, ValueMode::Cluster, f);
}

fn create_and_drop_index_mode<F>(test: &str, mode: ValueMode, f: F)
where
    F: FnOnce(&Persy, &str),
{
    create_and_drop(test, |persy| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.create_index::<u8, u8>("index1", mode)
            .expect("index created correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        f(persy, "index1");

        let mut tx = persy.begin().expect("begin transaction works");
        tx.drop_index("index1").expect("index created correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
    });
}

#[test]
fn test_create_drop_index() {
    create_and_drop("create_drop_index", |persy| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.create_index::<u8, u8>("index1", ValueMode::Cluster)
            .expect("index created correctly");
        assert!(tx.exists_index("index1").expect("exists works"));
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
        assert!(persy.exists_index("index1").expect("exists works"));

        let mut tx = persy.begin().expect("begin transaction works");
        tx.drop_index("index1").expect("index created correctly");
        assert!(!tx.exists_index("index1").expect("exists works"));
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
        assert!(!persy.exists_index("index1").expect("exists works"));
    });
}

#[test]
fn test_create_duplicate_index() {
    create_and_drop("create_duplicate_index", |persy| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.create_index::<u8, u8>("index1", ValueMode::Cluster)
            .expect("index created correctly");
        assert!(tx.exists_index("index1").expect("exists works"));

        let mut tx1 = persy.begin().expect("begin transaction works");
        assert!(!tx1.exists_index("index1").expect("exists works"));
        tx1.create_index::<u8, u8>("index1", ValueMode::Cluster)
            .expect("index created correctly");
        assert!(tx1.exists_index("index1").expect("exists works"));
        let prep = tx1.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        match tx.prepare() {
            Err(PE::PE(persy::PrepareError::IndexAlreadyExists)) => {}
            _ => panic!("Expect duplicate index error"),
        }

        assert!(persy.exists_index("index1").expect("exists works"));
    });
}

#[test]
fn test_create_put_index_same_tx() {
    create_and_drop("create_crate_put", |persy| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.create_index::<u8, u8>("index1", ValueMode::Cluster)
            .expect("index created correctly");
        tx.put::<u8, u8>("index1", 10, 12).expect("put works correctly");
        tx.put::<u8, u8>("index1", 11, 12).expect("put works correctly");
        tx.put::<u8, u8>("index1", 12, 12).expect("put works correctly");
        tx.put::<u8, u8>("index1", 13, 12).expect("put works correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
        let mut res = persy.get::<u8, u8>("index1", &10).expect("get works correctly");
        assert_eq!(Some(12), res.next());
        let mut res = persy.get::<u8, u8>("index1", &11).expect("get works correctly");
        assert_eq!(Some(12), res.next());
        let mut res = persy.get::<u8, u8>("index1", &12).expect("get works correctly");
        assert_eq!(Some(12), res.next());
        let mut res = persy.get::<u8, u8>("index1", &13).expect("get works correctly");
        assert_eq!(Some(12), res.next());
        let res = persy.range::<u8, u8, _>("index1", ..).expect("get works correctly");
        assert_eq!(4, res.count());

        let mut tx = persy.begin().expect("begin transaction works");
        tx.drop_index("index1").expect("index created correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
    });
}

#[test]
fn test_create_put_remove_get_drop_index_same_tx() {
    create_and_drop("create_put_remove_get_drop_index", |persy| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.create_index::<u8, u8>("index1", ValueMode::Cluster)
            .expect("index created correctly");
        tx.put::<u8, u8>("index1", 10, 12).expect("put works correctly");
        let mut res = tx.get::<u8, u8>("index1", &10).expect("get works correctly");
        assert_eq!(Some(12), res.next());
        tx.remove::<u8, u8>("index1", 10, None).expect("put works correctly");
        let res = tx.get::<u8, u8>("index1", &10).expect("get works correctly");
        assert_eq!(0, res.len());

        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
        let mut tx = persy.begin().expect("begin transaction works");
        tx.drop_index("index1").expect("index created correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
    });
}

#[derive(Debug)]
struct TErr {
    _pe: PersyError,
}
impl<T: Into<PersyError>> From<PE<T>> for TErr {
    fn from(e: PE<T>) -> Self {
        TErr { _pe: e.error().into() }
    }
}

fn test_for_type<K: IndexType, V>(persy: &Persy, name: &str, k: K, v: V) -> Result<(), TErr>
where
    V: IndexType + std::fmt::Debug + PartialEq,
{
    let mut tx = persy.begin()?;
    tx.create_index::<K, V>(name, ValueMode::Cluster)?;
    tx.put::<K, V>(name, k.clone(), v.clone())?;
    let mut res = tx.get::<K, V>(name, &k)?;
    assert_eq!(Some(v.clone()), res.next());
    let prep = tx.prepare()?;
    prep.commit()?;

    let mut res = persy.get::<K, V>(name, &k)?;
    assert_eq!(Some(v), res.next());
    let mut tx = persy.begin()?;
    tx.remove::<K, V>(name, k.clone(), None)?;
    let res = tx.get::<K, V>(name, &k)?;
    assert!(res.len() == 0);
    let prep = tx.prepare()?;
    prep.commit()?;

    let res = persy.get::<K, V>(name, &k)?;
    assert!(res.len() == 0);
    let mut tx = persy.begin()?;
    tx.drop_index(name)?;
    let prep = tx.prepare()?;
    prep.commit()?;
    Ok(())
}

#[test]
fn test_all_indexable_types() {
    create_and_drop("all_indexable_types", |persy| {
        test_for_type::<u8, u8>(persy, "idx_u8", 10, 10).expect("test pass");
        test_for_type::<u16, u16>(persy, "idx_u16", 10, 10).expect("test pass");
        test_for_type::<u32, u32>(persy, "idx_u32", 10, 10).expect("test pass");
        test_for_type::<u64, u64>(persy, "idx_u64", 10, 10).expect("test pass");
        test_for_type::<u128, u128>(persy, "idx_u128", 10, 10).expect("test pass");
        test_for_type::<i8, i8>(persy, "idx_i8", 10, 10).expect("test pass");
        test_for_type::<i16, i16>(persy, "idx_i16", 10, 10).expect("test pass");
        test_for_type::<i32, i32>(persy, "idx_i32", 10, 10).expect("test pass");
        test_for_type::<i64, i64>(persy, "idx_i64", 10, 10).expect("test pass");
        test_for_type::<i128, i128>(persy, "idx_i128", 10, 10).expect("test pass");
        test_for_type::<f32, f32>(persy, "idx_f32", 10.0, 10.0).expect("test pass");
        test_for_type::<f64, f64>(persy, "idx_f64", 10.0, 10.0).expect("test pass");
        test_for_type::<String, String>(persy, "idx_string", "key".to_string(), "value".to_string())
            .expect("test pass");
        test_for_type::<ByteVec, ByteVec>(persy, "idx_bytevec", vec![10; 10].into(), vec![10; 10].into())
            .expect("test pass");
    });
}

#[test]
fn test_put_get_index() {
    create_and_drop_index("create_drop_index", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));
    });
}

#[test]
fn test_put_get_tx_index() {
    create_and_drop_index("create_put_get_tx_index", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        let mut res = tx.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));
    });
}

#[test]
fn test_put_remove_index() {
    create_and_drop_index("create_put_remove_index", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));

        let mut tx = persy.begin().expect("begin transaction works");
        tx.remove::<u8, u8>(index_name, 10, None).expect("put works correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.len(), 0);
    });
}

#[test]
fn test_duplicate_put() {
    create_and_drop_index_mode("duplicate_put", ValueMode::Exclusive, |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        tx.put::<u8, u8>(index_name, 10, 20).expect("put works correctly");
        assert!(tx.prepare().is_err());
    });
}

#[test]
fn test_same_value_no_duplicate_put() {
    create_and_drop_index_mode("same_value_no_duplicate", ValueMode::Exclusive, |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));
    });
}

#[test]
fn test_duplicate_second_put() {
    create_and_drop_index_mode("create_drop_index", ValueMode::Exclusive, |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");

        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 20).expect("put works correctly");
        assert!(tx.prepare().is_err());
    });
}

#[test]
fn test_duplicate_tx_put() {
    create_and_drop_index_mode("duplicate_put_tx", ValueMode::Exclusive, |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        tx.put::<u8, u8>(index_name, 10, 20).expect("put works correctly");
        assert!(tx.get::<u8, u8>(index_name, &10).is_err());
    });
}

#[test]
fn test_same_value_no_duplicate_put_tx() {
    create_and_drop_index_mode(
        "some_value_no_duplicate_put_tx",
        ValueMode::Exclusive,
        |persy, index_name| {
            let mut tx = persy.begin().expect("begin transaction works");
            tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
            tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
            let mut value = tx.get::<u8, u8>(index_name, &10).expect("get works");
            assert_eq!(value.next(), Some(12));
        },
    );
}

#[test]
fn test_put_one_index() {
    create_and_drop_index("put_one_index", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        let res = tx.one::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res, Some(12));
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
        let snap = persy.snapshot().expect("snapshot ok");
        let res = snap.one::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res, Some(12));
        let res = persy.one::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res, Some(12));
    });
}

#[test]
fn test_put_remove_index_one_tx() {
    create_and_drop_index("put_remove_index_one", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        tx.remove::<u8, u8>(index_name, 10, None).expect("put works correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.len(), 0);
    });
}

#[test]
fn test_multiple_values_put_get() {
    create_and_drop_index("multiple_values_put", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");

        tx.put::<u8, u8>(index_name, 10, 14).expect("put works correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.collect::<Vec<_>>(), vec![12, 14]);
    });
}

#[test]
fn test_multiple_values_put_get_tx() {
    create_and_drop_index("multiple_values_put_get_tx", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");

        tx.put::<u8, u8>(index_name, 10, 14).expect("put works correctly");
        let res = tx.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.collect::<Vec<_>>(), vec![12, 14]);
    });
}

#[test]
fn test_multiple_put_same_value_get() {
    create_and_drop_index("multiple_put same_value_gut", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");

        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));
    });
}

#[test]
fn test_multiple_put_same_value_intervalled_get() {
    create_and_drop_index("multiple_put same_value_intervalled_get", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 13).expect("put works correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 14).expect("put works correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        let mut res = tx.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));
        assert_eq!(res.next(), Some(13));
        assert_eq!(res.next(), Some(14));
        assert_eq!(res.next(), None);
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));
        assert_eq!(res.next(), Some(13));
        assert_eq!(res.next(), Some(14));
        assert_eq!(res.next(), None);
    });
}

#[test]
fn test_multiple_put_remove_same_value_intervalled_get() {
    create_and_drop_index("multiple_put remove_same_value_intervalled_get", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        tx.put::<u8, u8>(index_name, 10, 13).expect("put works correctly");
        tx.put::<u8, u8>(index_name, 10, 14).expect("put works correctly");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");

        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
        let mut res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));
        assert_eq!(res.next(), Some(13));
        assert_eq!(res.next(), Some(14));
        assert_eq!(res.next(), None);

        let mut tx = persy.begin().expect("begin transaction works");
        tx.remove::<u8, u8>(index_name, 10, Some(12))
            .expect("put works correctly");
        tx.remove::<u8, u8>(index_name, 10, Some(11))
            .expect("put works correctly");
        tx.remove::<u8, u8>(index_name, 10, Some(13))
            .expect("put works correctly");
        tx.remove::<u8, u8>(index_name, 10, Some(12))
            .expect("put works correctly");
        tx.remove::<u8, u8>(index_name, 10, Some(13))
            .expect("put works correctly");
        let mut res = tx.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(14));
        assert_eq!(res.next(), None);
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(14));
        assert_eq!(res.next(), None);
    });
}
#[test]
fn test_multiple_put_same_value_intervalled_get_same_tx() {
    create_and_drop_index(
        "multiple_put same_value_intervalled_get_same_tx",
        |persy, index_name| {
            let mut tx = persy.begin().expect("begin transaction works");
            tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
            tx.put::<u8, u8>(index_name, 10, 13).expect("put works correctly");
            tx.put::<u8, u8>(index_name, 10, 14).expect("put works correctly");
            tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");

            let mut res = tx.get::<u8, u8>(index_name, &10).expect("get works correctly");
            assert_eq!(res.next(), Some(12));
            assert_eq!(res.next(), Some(13));
            assert_eq!(res.next(), Some(14));
            assert_eq!(res.next(), None);
            let prep = tx.prepare().expect("prepare with index works");
            prep.commit().expect("commit with index works");

            let mut res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
            assert_eq!(res.next(), Some(12));
            assert_eq!(res.next(), Some(13));
            assert_eq!(res.next(), Some(14));
            assert_eq!(res.next(), None);
        },
    );
}

#[test]
fn test_multiple_put_same_value_inverted_order_get_same_tx() {
    create_and_drop_index("multiple_put same_value_inverted_get_same_tx", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        tx.put::<u8, u8>(index_name, 10, 11).expect("put works correctly");
        tx.put::<u8, u8>(index_name, 10, 13).expect("put works correctly");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        tx.put::<u8, u8>(index_name, 10, 13).expect("put works correctly");

        let mut res = tx.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(11));
        assert_eq!(res.next(), Some(12));
        assert_eq!(res.next(), Some(13));
        assert_eq!(res.next(), None);
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(11));
        assert_eq!(res.next(), Some(12));
        assert_eq!(res.next(), Some(13));
        assert_eq!(res.next(), None);
    });
}

#[test]
fn test_multiple_put_remove_same_value_inverted_order_get_same_tx() {
    create_and_drop_index(
        "multiple_put_remove_same_value_inverted_order_get_same_tx",
        |persy, index_name| {
            let mut tx = persy.begin().expect("begin transaction works");
            tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
            tx.put::<u8, u8>(index_name, 10, 11).expect("put works correctly");
            tx.put::<u8, u8>(index_name, 10, 13).expect("put works correctly");
            tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
            tx.put::<u8, u8>(index_name, 10, 13).expect("put works correctly");

            let mut res = tx.get::<u8, u8>(index_name, &10).expect("get works correctly");
            assert_eq!(res.next(), Some(11));
            assert_eq!(res.next(), Some(12));
            assert_eq!(res.next(), Some(13));
            assert_eq!(res.next(), None);
            tx.remove::<u8, u8>(index_name, 10, Some(12))
                .expect("put works correctly");
            tx.remove::<u8, u8>(index_name, 10, Some(11))
                .expect("put works correctly");
            tx.remove::<u8, u8>(index_name, 10, Some(13))
                .expect("put works correctly");
            tx.remove::<u8, u8>(index_name, 10, Some(12))
                .expect("put works correctly");
            tx.remove::<u8, u8>(index_name, 10, Some(13))
                .expect("put works correctly");
            let mut res = tx.get::<u8, u8>(index_name, &10).expect("get works correctly");
            assert_eq!(res.next(), None);
            let prep = tx.prepare().expect("prepare with index works");
            prep.commit().expect("commit with index works");

            let mut res = persy.get::<u8, u8>(index_name, &10).expect("get works correctly");
            assert_eq!(res.next(), None);
        },
    );
}

#[test]
fn test_index_browse() {
    create_and_drop_index("test_index_browse", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        for n in 10..30 {
            tx.put::<u8, u8>(index_name, n, 12).expect("put works correctly");
        }

        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let start = 10;
        let to = 29;
        let mut count = to - start;
        let mut iter: IndexIter<u8, u8> = persy.range(index_name, ..).expect("browse works correctly");
        assert_eq!(iter.next().unwrap().0, start);
        let mut last = None;
        for mut x in iter {
            last = Some(x.0.clone());
            assert_eq!(x.1.next(), Some(12));
            count -= 1;
        }
        assert_eq!(Some(to), last);
        assert_eq!(0, count);
    });
}

#[test]
fn test_index_range() {
    create_and_drop_index("test_index_range", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        for n in 10..30 {
            tx.put::<u8, u8>(index_name, n, 12).expect("put works correctly");
        }

        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let start = 13;
        let to = 24;
        let mut count = to - start;
        let mut iter: IndexIter<u8, u8> = persy.range(index_name, start..=to).expect("range works correctly");
        assert_eq!(iter.next().unwrap().0, start);
        let mut last = None;
        for mut x in iter {
            last = Some(x.0.clone());
            assert_eq!(x.1.next(), Some(12));
            count -= 1;
        }
        assert_eq!(Some(to), last);
        assert_eq!(0, count);
    });
}

#[test]
fn test_index_range_rev() {
    create_and_drop_index("test_index_range_rev", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        for n in 10..30 {
            tx.put::<u8, u8>(index_name, n, 12).expect("put works correctly");
        }

        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let start = 13;
        let to = 24;
        let mut count = to - start;
        let base: IndexIter<u8, u8> = persy.range(index_name, start..=to).expect("range works correctly");
        let mut iter = base.rev();
        assert_eq!(iter.next().unwrap().0, to);
        let mut last = None;
        for mut x in iter {
            last = Some(x.0.clone());
            assert_eq!(x.1.next(), Some(12));
            count -= 1;
        }
        assert_eq!(Some(start), last);
        assert_eq!(0, count);
    });
}

#[test]
fn test_index_range_miss_direct_rev() {
    create_and_drop_index("test_index_range_miss_direct_rev", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        for n in 20..30 {
            tx.put::<u8, u8>(index_name, n, n).expect("put works correctly");
        }
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut base: IndexIter<u8, u8> = persy.range(index_name, ..=5).expect("range works correctly");
        assert!(base.next().is_none());
        let mut iter = base.rev();
        assert!(iter.next().is_none());
        let mut base: IndexIter<u8, u8> = persy.range(index_name, 40..).expect("range works correctly");
        assert!(base.next().is_none());
        let mut iter = base.rev();
        assert!(iter.next().is_none());
        let mut base: IndexIter<u8, u8> = persy.range(index_name, 2..8).expect("range works correctly");
        assert!(base.next().is_none());
        let mut iter = base.rev();
        assert!(iter.next().is_none());
    });
}

#[test]
fn test_index_range_miss_direct_rev_tx() {
    create_and_drop_index("test_index_range_miss_direct_rev", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        for n in 20..30 {
            tx.put::<u8, u8>(index_name, n, n).expect("put works correctly");
        }

        let mut base: TxIndexIter<u8, u8> = tx.range(index_name, ..=5).expect("range works correctly");
        assert!(base.next().is_none());
        let mut iter = base.rev();
        assert!(iter.next().is_none());
        let mut base: TxIndexIter<u8, u8> = tx.range(index_name, 40..).expect("range works correctly");
        assert!(base.next().is_none());
        let mut iter = base.rev();
        assert!(iter.next().is_none());
        let mut base: TxIndexIter<u8, u8> = tx.range(index_name, 2..8).expect("range works correctly");
        assert!(base.next().is_none());
        let mut iter = base.rev();
        assert!(iter.next().is_none());
        let mut base: TxIndexIter<u8, u8> = tx.range(index_name, 28..40).expect("range works correctly");
        assert_eq!(base.next().unwrap().1.next(), Some(28));
        let mut iter = base.rev();
        assert_eq!(iter.next().unwrap().1.next(), Some(29));
        assert!(iter.next().is_none());
    });
}

#[test]
fn test_index_browse_tx() {
    create_and_drop_index("test_index_browse_tx", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        for n in 10..30 {
            tx.put::<u8, u8>(index_name, n, 12).expect("put works correctly");
        }
        let start = 10;
        let to = 29;
        let mut count = to - start;
        let mut last = None;
        {
            let mut iter: TxIndexIter<u8, u8> = tx.range(index_name, ..).expect("browse works correctly");
            assert_eq!(iter.next().unwrap().0, start);
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                count -= 1;
            }
        }
        assert_eq!(Some(to), last);
        assert_eq!(0, count);
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
    });
}

#[test]
fn test_index_range_tx() {
    create_and_drop_index("test_index_range_tx", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        for n in 10..30 {
            tx.put::<u8, u8>(index_name, n, 12).expect("put works correctly");
        }
        tx.remove::<u8, u8>(index_name, 20, None).expect("remove works");

        let start = 13;
        let to = 24;
        let mut count = to - start - 1;
        {
            let mut iter: TxIndexIter<u8, u8> = tx.range(index_name, start..=to).expect("range works correctly");
            assert_eq!(iter.next().unwrap().0, start);
            let mut last = None;
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                assert!(x.0 != 20u8);
                count -= 1;
            }
            assert_eq!(Some(to), last);
            assert_eq!(0, count);
        }

        let mut count = to - start - 2;
        {
            let mut iter: TxIndexIter<u8, u8> = tx.range(index_name, start..to).expect("range works correctly");
            assert_eq!(iter.next().unwrap().0, start);
            let mut last = None;
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                assert!(x.0 != 20u8);
                count -= 1;
            }
            assert_eq!(Some(to - 1), last);
            assert_eq!(0, count);
        }

        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
    });
}

#[test]
fn test_index_range_tx_off() {
    create_and_drop_index("test_index_range_tx_off", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        for n in 10..30 {
            tx.put::<u8, u8>(index_name, n * 2, 12).expect("put works correctly");
        }
        tx.remove::<u8, u8>(index_name, 20, None).expect("remove works");

        let start = 23;
        let to = 39;
        let mut count = (to - start) / 2 - 1;
        {
            let mut iter: TxIndexIter<u8, u8> = tx.range(index_name, start..=to).expect("range works correctly");
            assert_eq!(iter.next().unwrap().0, start + 1);
            let mut last = None;
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                assert!(x.0 != 20u8);
                count -= 1;
            }
            assert_eq!(Some(to - 1), last);
            assert_eq!(0, count);
        }

        let mut count = (to - start) / 2 - 1;
        {
            let mut iter: TxIndexIter<u8, u8> = tx.range(index_name, start..to).expect("range works correctly");
            assert_eq!(iter.next().unwrap().0, start + 1);
            let mut last = None;
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                assert!(x.0 != 20u8);
                count -= 1;
            }
            assert_eq!(Some(to - 1), last);
            assert_eq!(0, count);
        }

        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
    });
}

#[test]
fn test_index_range_tx_access() {
    create_and_drop_index("test_index_range_tx_access", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.create_segment("seg").expect("create segment");
        for n in 10..30 {
            tx.put::<u8, u8>(index_name, n, 12).expect("put works correctly");
        }

        let start = 13;
        let to = 24;
        let mut count = to - start;
        {
            let mut iter: TxIndexIter<u8, u8> = tx.range(index_name, start..=to).expect("range works correctly");
            assert_eq!(iter.next().unwrap().0, start);
            iter.tx().insert("seg", "data".as_bytes()).expect("insert works");
            let mut last = None;
            while let Some(mut x) = iter.next_tx() {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                x.2.insert("seg", "data".as_bytes()).expect("insert works");
                count -= 1;
            }
            assert_eq!(Some(to), last);
            assert_eq!(0, count);
        }

        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
    });
}

#[test]
fn test_index_range_tx_rev() {
    create_and_drop_index("test_index_range_tx_rev", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        for n in 10..30 {
            tx.put::<u8, u8>(index_name, n, 12).expect("put works correctly");
        }
        tx.remove::<u8, u8>(index_name, 20, None).expect("remove works");

        let start = 13;
        let to = 24;
        let mut count = to - start - 1;
        {
            let base: TxIndexIter<u8, u8> = tx.range(index_name, start..=to).expect("range works correctly");
            let mut iter = base.rev();
            assert_eq!(iter.next().unwrap().0, to);
            let mut last = None;
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                assert!(x.0 != 20u8);
                count -= 1;
            }
            assert_eq!(Some(start), last);
            assert_eq!(0, count);
        }

        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
    });
}

#[test]
fn test_index_range_tx_change_committed() {
    create_and_drop_index("test_index_range_tx", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        for n in 10..30 {
            tx.put::<u8, u8>(index_name, n, 12).expect("put works correctly");
        }
        tx.prepare().expect("prepare works").commit().expect("commit works");
        let mut tx = persy.begin().expect("begin transaction works");
        tx.remove::<u8, u8>(index_name, 20, None).expect("remove works");
        tx.put::<u8, u8>(index_name, 31, 12).expect("put works correctly");

        let start = 13;
        let to = 31;
        let mut count = to - start - 2;
        {
            let mut iter: TxIndexIter<u8, u8> = tx.range(index_name, start..=to).expect("range works correctly");
            assert_eq!(iter.next().unwrap().0, start);
            let mut last = None;
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                assert!(x.0 != 20u8);
                count -= 1;
            }
            assert_eq!(Some(to), last);
            assert_eq!(0, count);
        }
        let mut count = to - start - 2;
        {
            let base: TxIndexIter<u8, u8> = tx.range(index_name, start..=to).expect("range works correctly");
            let mut iter = base.rev();
            assert_eq!(iter.next().unwrap().0, to);
            let mut last = None;
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                assert!(x.0 != 20u8);
                count -= 1;
            }
            assert_eq!(Some(start), last);
            assert_eq!(0, count);
        }

        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
    });
}

#[test]
fn test_index_range_tx_multiple_change_committed() {
    create_and_drop_index("test_index_range_tx", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        for n in 10..30 {
            tx.put::<u8, u8>(index_name, n, 12).expect("put works correctly");
        }
        tx.prepare().expect("prepare works").commit().expect("commit works");
        let mut tx = persy.begin().expect("begin transaction works");
        for n in 10..20 {
            tx.remove::<u8, u8>(index_name, n, None).expect("remove works");
        }

        for n in 5..20 {
            tx.put::<u8, u8>(index_name, n, 12).expect("put works");
        }

        let start = 5;
        let to = 25;
        let mut count = to - start;
        {
            let mut iter: TxIndexIter<u8, u8> = tx.range(index_name, start..=to).expect("range works correctly");
            assert_eq!(iter.next().unwrap().0, start);
            let mut last = None;
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                count -= 1;
            }
            assert_eq!(Some(to), last);
            assert_eq!(0, count);
        }
        let mut count = to - start;
        {
            let base: TxIndexIter<u8, u8> = tx.range(index_name, start..=to).expect("range works correctly");
            let mut iter = base.rev();
            assert_eq!(iter.next().unwrap().0, to);
            let mut last = None;
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                count -= 1;
            }
            assert_eq!(Some(start), last);
            assert_eq!(0, count);
        }

        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
    });
}

#[test]
fn test_range_tx_created_in_tx() {
    create_and_drop("range_created_in_tx", |persy| {
        let index_name = "index1";
        let mut tx = persy.begin().expect("begin transaction works");
        tx.create_index::<u8, u8>(index_name, ValueMode::Cluster)
            .expect("index created correctly");

        for n in 10..30 {
            tx.put::<u8, u8>(index_name, n, 12).expect("put works correctly");
        }

        let start = 13;
        let to = 24;
        let mut count = to - start;
        {
            let mut iter: TxIndexIter<u8, u8> = tx.range(index_name, start..=to).expect("range works correctly");
            assert_eq!(iter.next().unwrap().0, start);
            let mut last = None;
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                count -= 1;
            }
            assert_eq!(Some(to), last);
            assert_eq!(0, count);
        }

        let mut count = to - start - 1;
        {
            let mut iter: TxIndexIter<u8, u8> = tx.range(index_name, start..to).expect("range works correctly");
            assert_eq!(iter.next().unwrap().0, start);
            let mut last = None;
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                count -= 1;
            }
            assert_eq!(Some(to - 1), last);
            assert_eq!(0, count);
        }

        let mut count = to - start;
        {
            let base: TxIndexIter<u8, u8> = tx.range(index_name, start..=to).expect("range works correctly");
            let mut iter = base.rev();
            assert_eq!(iter.next().unwrap().0, to);
            let mut last = None;
            for mut x in iter {
                last = Some(x.0.clone());
                assert_eq!(x.1.next(), Some(12));
                count -= 1;
            }
            assert_eq!(Some(start), last);
            assert_eq!(0, count);
        }

        let mut base: TxIndexIter<u8, u8> = tx.range(index_name, 100..=200).expect("range works correctly");
        assert!(base.next().is_none());
        let base: TxIndexIter<u8, u8> = tx.range(index_name, 100..=200).expect("range works correctly");
        assert!(base.rev().next().is_none());
        tx.prepare()
            .expect("prepeare successfult")
            .commit()
            .expect("commit successful");
        let mut tx = persy.begin().expect("begin transaction works");
        tx.drop_index("index1").expect("index created correctly");
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
    });
}

#[test]
fn test_mupltiple_put_same_value_get_tx() {
    create_and_drop_index("create_drop_index", |persy, index_name| {
        let mut tx = persy.begin().expect("begin transaction works");
        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");

        tx.put::<u8, u8>(index_name, 10, 12).expect("put works correctly");
        let mut res = tx.get::<u8, u8>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));
    });
}

#[test]
pub fn test_list_indexes() {
    create_and_drop("test_list_indexes", |persy| {
        let mut tx = persy.begin().expect("error on transaction begin");
        tx.create_index::<u8, u8>("one", ValueMode::Replace)
            .expect("error on index creation");
        tx.create_index::<u32, u32>("two", ValueMode::Replace)
            .expect("error on index creation");
        let fin = tx.prepare().expect("error on commit prepare");
        fin.commit().expect("error on commit");
        let indexes = persy.list_indexes().expect("list indexes works as expected");
        assert_eq!(indexes.len(), 2);
        let names = indexes.into_iter().map(|x| x.0).collect::<Vec<String>>();
        assert!(names.contains(&"one".to_string()));
        assert!(names.contains(&"two".to_string()));
        let segments = persy.list_segments().expect("list segments works as expected");
        assert_eq!(segments.len(), 0);
    });
}

#[test]
pub fn test_list_indexes_tx() {
    create_and_drop("test_list_indexes", |persy| {
        let mut tx = persy.begin().expect("error on transaction begin");
        tx.create_index::<u8, u8>("one", ValueMode::Replace)
            .expect("error on index creation");
        tx.create_index::<u32, u32>("two", ValueMode::Replace)
            .expect("error on index creation");
        let fin = tx.prepare().expect("error on commit prepare");
        fin.commit().expect("error on commit");
        let mut tx = persy.begin().expect("error on transaction begin");
        tx.create_index::<u8, u8>("three", ValueMode::Replace)
            .expect("error on index creation");
        tx.drop_index("two").expect("error on index creation");

        let indexes = tx.list_indexes().expect("list indexes works as expected");
        assert_eq!(indexes.len(), 2);
        let names = indexes.into_iter().map(|x| x.0).collect::<Vec<String>>();
        assert!(names.contains(&"one".to_string()));
        assert!(names.contains(&"three".to_string()));

        let segments = tx.list_segments().expect("list segments works as expected");
        assert_eq!(segments.len(), 0);
    });
}

#[test]
fn test_grow_and_shrink() {
    create_and_drop("grow_and_shrink", |persy| {
        let mut tx = persy.begin().expect("begin transaction works");
        let index_name = "grow_and_shrink";
        tx.create_index::<i32, i32>(index_name, ValueMode::Cluster).unwrap();
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");
        let mut tx = persy.begin().expect("begin transaction works");
        for v in 0..1000 {
            tx.put::<i32, i32>(index_name, v, 12).expect("put works correctly");
            tx.put::<i32, i32>(index_name, v, 13).expect("put works correctly");
            tx.put::<i32, i32>(index_name, v, 14).expect("put works correctly");
            if v % 100 == 0 {
                let prep = tx.prepare().expect("prepare with index works");
                prep.commit().expect("commit with index works");
                tx = persy.begin().expect("begin transaction works");
            }
        }
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut res = persy.get::<i32, i32>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));
        assert_eq!(res.next(), Some(13));
        assert_eq!(res.next(), Some(14));
        assert_eq!(res.next(), None);
        let count = persy
            .range::<i32, i32, _>(index_name, ..)
            .expect("get works correctly")
            .count();
        assert_eq!(count, 1000);

        let mut tx = persy.begin().expect("begin transaction works");
        for v in 0..1000 {
            tx.remove::<i32, i32>(index_name, v, None).expect("put works correctly");
            if v % 100 == 0 {
                let prep = tx.prepare().expect("prepare with index works");
                prep.commit().expect("commit with index works");
                tx = persy.begin().expect("begin transaction works");
            }
        }
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let mut res = persy.get::<i32, i32>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), None);
        let count = persy
            .range::<i32, i32, _>(index_name, ..)
            .expect("get works correctly")
            .count();
        assert_eq!(count, 0);
    });
}

#[test]
fn test_big_delete_txs() {
    create_and_drop("big_delete_txs", |persy| {
        let mut tx = persy.begin().expect("begin transaction works");
        let index_name = "big_delete_txs";
        tx.create_index::<i32, i32>(index_name, ValueMode::Cluster).unwrap();
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        let all: Vec<i32> = (1..=100000).into_iter().collect();

        for chunk in all.chunks(20000) {
            let mut tx = persy.begin().expect("begin transaction works");
            for k in chunk {
                tx.put::<i32, i32>(index_name, *k, 12).expect("put works correctly");
            }
            let prep = tx.prepare().expect("prepare with index works");
            prep.commit().expect("commit with index works");
        }

        let mut res = persy.get::<i32, i32>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));

        for x in 1..10 {
            let iter = persy
                .range::<i32, i32, _>(index_name, ..)
                .expect("range works")
                .into_iter()
                .take(10000 as usize);

            let mut tx = persy.begin().expect("begin transaction works");
            let mut last = 0;
            for (id, _values) in iter {
                tx.remove::<i32, i32>(index_name, id, None)
                    .expect("put works correctly");
                last = id;
            }
            println!("last {}", last);

            let prep = tx.prepare().expect("prepare with index works");
            prep.commit().expect("commit with index works");

            let mut r = persy
                .range::<i32, i32, _>(index_name, ..)
                .expect("range works correctly");
            assert_eq!(r.next().map(|(k, _)| k), Some((x * 10000) + 1));
            let r = persy
                .range::<i32, i32, _>(index_name, ..)
                .expect("range works correctly");
            assert_eq!(r.rev().next().map(|(k, _)| k), Some(100000));
        }
    });
}

#[test]
fn test_less_big_delete_txs() {
    create_and_drop("less_big_delete_txs", |persy| {
        let mut tx = persy.begin().expect("begin transaction works");
        let index_name = "less_big_delete_txs";
        tx.create_index::<i32, i32>(index_name, ValueMode::Cluster).unwrap();
        let prep = tx.prepare().expect("prepare with index works");
        prep.commit().expect("commit with index works");

        for x in 0..80 {
            let mut tx = persy.begin().expect("begin transaction works");
            for k in 0..1000 {
                tx.put::<i32, i32>(index_name, (x * 1000) + k, 12)
                    .expect("put works correctly");
            }
            let prep = tx.prepare().expect("prepare with index works");
            prep.commit().expect("commit with index works");
        }

        #[cfg(feature = "experimental_inspect")]
        persy::inspect::PersyInspect::inspect_tree::<i32, i32, _>(
            persy,
            index_name,
            &mut persy::inspect::PrintTreeInspector::new(),
        )
        .unwrap();
        let mut res = persy.get::<i32, i32>(index_name, &10).expect("get works correctly");
        assert_eq!(res.next(), Some(12));

        for _x in 1..5 {
            let iter = persy
                .range::<i32, i32, _>(index_name, ..)
                .expect("range works")
                .into_iter()
                .take(10000 as usize);
            let val = iter.map(|(k, _)| k).collect::<Vec<_>>();
            println!("{:?}", val);
            let mut tx = persy.begin().expect("begin transaction works");
            let mut last = 0;
            for id in val {
                tx.remove::<i32, i32>(index_name, id, None)
                    .expect("put works correctly");
                last = id;
            }
            println!("last {}", last);

            let prep = tx.prepare().expect("prepare with index works");
            prep.commit().expect("commit with index works");

            #[cfg(feature = "experimental_inspect")]
            persy::inspect::PersyInspect::inspect_tree::<i32, i32, _>(
                persy,
                index_name,
                &mut persy::inspect::PrintTreeInspector::new(),
            )
            .unwrap();
            let mut r = persy
                .range::<i32, i32, _>(index_name, ..)
                .expect("range works correctly");
            assert_eq!(r.next().map(|(k, _)| k), Some(last + 1));
            let r = persy
                .range::<i32, i32, _>(index_name, ..)
                .expect("range works correctly");
            assert_eq!(r.rev().next().map(|(k, _)| k), Some(79999));
        }
    });
}