versatile-data 0.117.0

A library for databases that has convenient datasets that group together commonly used fields and gives you the flexibility to create your own fields.
Documentation
use std::num::NonZeroU32;

use hashbrown::HashMap;
use versatile_data::*;

fn new_data(name: &str) -> Data {
    let dir = std::env::temp_dir().join(format!("versatile-data-sort-{name}"));
    let _ = std::fs::remove_dir_all(&dir);
    Data::new(&dir, DataOption::default())
}

async fn insert(data: &mut Data, term_end: Term, fields: &[(&FieldName, &str)]) -> NonZeroU32 {
    let fields: HashMap<FieldName, Vec<u8>> = fields
        .iter()
        .map(|(name, value)| ((*name).clone(), value.as_bytes().to_vec()))
        .collect();
    data.insert(Activity::Active, Term::Default, term_end, fields)
        .await
}

#[test]
fn sort_by_last_updated_uses_last_updated() {
    let mut data = new_data("last-updated");
    let name = FieldName::new("name".into());
    futures::executor::block_on(async {
        // term_end decreases while last_updated increases.
        let r1 = insert(&mut data, Term::Overwrite(300), &[(&name, "a")]).await;
        std::thread::sleep(std::time::Duration::from_millis(1100));
        let r2 = insert(&mut data, Term::Overwrite(200), &[(&name, "b")]).await;
        std::thread::sleep(std::time::Duration::from_millis(1100));
        let r3 = insert(&mut data, Term::Overwrite(100), &[(&name, "c")]).await;

        let rows = data.all();
        let asc = data.sort(&rows, &[Order::Asc(OrderKey::LastUpdated)]);
        assert_eq!(asc, [r1, r2, r3]);
        let desc = data.sort(&rows, &[Order::Desc(OrderKey::LastUpdated)]);
        assert_eq!(desc, [r3, r2, r1]);
    });
}

#[test]
fn sort_by_field_keeps_rows_without_the_field() {
    let mut data = new_data("missing-field");
    let name = FieldName::new("name".into());
    let other = FieldName::new("other".into());
    futures::executor::block_on(async {
        let b = insert(&mut data, Term::Default, &[(&name, "b")]).await;
        let none = insert(&mut data, Term::Default, &[(&other, "x")]).await;
        let a = insert(&mut data, Term::Default, &[(&name, "a")]).await;

        let rows = data.all();
        let asc = data.sort(&rows, &[Order::Asc(OrderKey::Field(name.clone()))]);
        assert_eq!(asc, [a, b, none]);
        let desc = data.sort(&rows, &[Order::Desc(OrderKey::Field(name.clone()))]);
        assert_eq!(desc, [b, a, none]);
    });
}

#[test]
fn sub_sort_by_field_with_rows_without_the_field() {
    let mut data = new_data("missing-sub-field");
    let group = FieldName::new("group".into());
    let name = FieldName::new("name".into());
    futures::executor::block_on(async {
        let none = insert(&mut data, Term::Default, &[(&group, "g")]).await;
        let b = insert(&mut data, Term::Default, &[(&group, "g"), (&name, "b")]).await;
        let a = insert(&mut data, Term::Default, &[(&group, "g"), (&name, "a")]).await;

        let rows = data.all();
        let sorted = data.sort(
            &rows,
            &[
                Order::Asc(OrderKey::Field(group.clone())),
                Order::Asc(OrderKey::Field(name.clone())),
            ],
        );
        assert_eq!(sorted, [a, b, none]);
    });
}