structsy 0.5.2

Simple single file structs database
Documentation
use structsy::{Structsy, StructsyTx};
use structsy_derive::Persistent;
use tempfile::tempdir;

#[derive(Persistent)]
struct DataV0 {
    name: String,
}

#[derive(Persistent)]
struct DataV1 {
    name: String,
    size: u32,
}

impl From<DataV0> for DataV1 {
    fn from(data: DataV0) -> DataV1 {
        DataV1 {
            name: data.name,
            size: 0,
        }
    }
}

#[test]
fn test_migration() {
    let dir = tempdir().expect("can make a tempdir");
    let file = dir.path().join("test_migration.stry");
    {
        let db = Structsy::open(file.clone()).unwrap();
        db.define::<DataV0>().unwrap();
        let mut tx = db.begin().unwrap();
        tx.insert(&DataV0 {
            name: "aaa".to_string(),
        })
        .unwrap();
        tx.commit().unwrap();
    }
    {
        let prep = Structsy::prepare_open(file).unwrap();
        prep.migrate::<DataV0, DataV1>().unwrap();
        let db = prep.open().unwrap();
        db.define::<DataV1>().unwrap();
        let found = db.scan::<DataV1>().unwrap().next().unwrap();
        assert_eq!(&found.1.name, "aaa");
        assert_eq!(found.1.size, 0);
    }
}

#[test]
fn test_double_migration() {
    let dir = tempdir().expect("can make a tempdir");
    let file = dir.path().join("test_migration.stry");
    {
        let db = Structsy::open(file.clone()).unwrap();
        db.define::<DataV0>().unwrap();
        let mut tx = db.begin().unwrap();
        tx.insert(&DataV0 {
            name: "aaa".to_string(),
        })
        .unwrap();
        tx.commit().unwrap();
    }
    {
        let prep = Structsy::prepare_open(file.clone()).unwrap();
        prep.migrate::<DataV0, DataV1>().unwrap();
        let db = prep.open().unwrap();
        db.define::<DataV1>().unwrap();
        let found = db.scan::<DataV1>().unwrap().next().unwrap();
        assert_eq!(&found.1.name, "aaa");
        assert_eq!(found.1.size, 0);
    }
    {
        let prep = Structsy::prepare_open(file).unwrap();
        prep.migrate::<DataV0, DataV1>().unwrap();
        let db = prep.open().unwrap();
        db.define::<DataV1>().unwrap();
        let found = db.scan::<DataV1>().unwrap().next().unwrap();
        assert_eq!(&found.1.name, "aaa");
        assert_eq!(found.1.size, 0);
    }
}

mod first {

    use std::path::PathBuf;
    use structsy::{Ref, SRes, Structsy, StructsyTx};
    use structsy_derive::Persistent;

    #[derive(Persistent)]
    struct DataV0 {
        name: String,
    }
    type Data = DataV0;

    #[derive(Persistent)]
    struct DataRef {
        data: Ref<Data>,
    }

    pub fn first_operation(file: PathBuf) -> SRes<()> {
        let db = Structsy::open(file.clone())?;
        db.define::<Data>()?;
        db.define::<DataRef>()?;
        let mut tx = db.begin()?;
        let id = tx.insert(&Data {
            name: "aaa".to_string(),
        })?;

        tx.insert(&DataRef { data: id })?;
        tx.commit()?;
        Ok(())
    }
}

mod second {

    use std::path::PathBuf;

    use structsy::{Ref, SRes, Structsy};
    use structsy_derive::Persistent;

    #[derive(Persistent)]
    struct DataV0 {
        name: String,
    }
    #[derive(Persistent)]
    struct DataV1 {
        name: String,
        size: u32,
    }

    impl From<DataV0> for DataV1 {
        fn from(dt: DataV0) -> Self {
            DataV1 { name: dt.name, size: 0 }
        }
    }

    type Data = DataV1;

    #[derive(Persistent)]
    struct DataRef {
        data: Ref<Data>,
    }

    pub fn second_operation(file: PathBuf) -> SRes<()> {
        let prep = Structsy::prepare_open(file)?;
        prep.migrate::<DataV0, DataV1>()?;
        let db = prep.open()?;
        db.define::<Data>()?;
        db.define::<DataRef>()?;
        let found = db.scan::<Data>()?.next().unwrap();
        assert_eq!(&found.1.name, "aaa");
        assert_eq!(found.1.size, 0);
        let ref_found = db.scan::<DataRef>()?.next().unwrap();
        assert_eq!(ref_found.1.data, found.0);
        Ok(())
    }
}
mod third {

    use std::path::PathBuf;

    use structsy::{Ref, SRes, Structsy};
    use structsy_derive::Persistent;

    #[derive(Persistent)]
    struct DataV0 {
        name: String,
    }
    #[derive(Persistent)]
    struct DataV1 {
        name: String,
        size: u32,
    }

    impl From<DataV0> for DataV1 {
        fn from(dt: DataV0) -> Self {
            DataV1 { name: dt.name, size: 0 }
        }
    }

    #[derive(Persistent)]
    struct DataV2 {
        name: String,
        size: u32,
        surname: String,
    }

    impl From<DataV1> for DataV2 {
        fn from(dt: DataV1) -> Self {
            DataV2 {
                name: dt.name,
                size: 0,
                surname: "Doe".to_owned(),
            }
        }
    }

    type Data = DataV2;

    #[derive(Persistent)]
    struct DataRef {
        data: Ref<Data>,
    }

    pub fn third_operation(file: PathBuf) -> SRes<()> {
        let prep = Structsy::prepare_open(file)?;
        prep.migrate::<DataV0, DataV1>()?;
        prep.migrate::<DataV1, DataV2>()?;
        let db = prep.open()?;
        db.define::<Data>()?;
        db.define::<DataRef>()?;
        let found = db.scan::<Data>()?.next().unwrap();
        assert_eq!(&found.1.name, "aaa");
        assert_eq!(found.1.size, 0);
        assert_eq!(found.1.surname, "Doe");
        let ref_found = db.scan::<DataRef>()?.next().unwrap();
        assert_eq!(ref_found.1.data, found.0);
        Ok(())
    }
}

#[test]
fn test_ref_migration() {
    let dir = tempdir().expect("can make a tempdir");
    let file = dir.path().join("test_migration.stry");
    first::first_operation(file.clone()).unwrap();
    second::second_operation(file.clone()).unwrap();
    third::third_operation(file).unwrap();
}