jasondb 0.2.7

A Blazingly-Fast, JSON-Based, Log-Structured Database.
Documentation
use crate::sources::{FileSource, Source};

use humphrey_json::prelude::*;

use std::fs::{self, File};
use std::io::{Read, Seek, Write};

#[test]
fn read_write() {
    let mut database = FileSource::new("test_read_write.jdb").unwrap();

    let index_1 = database.write_entry("key1", "this is a value").unwrap();
    let index_2 = database.write_entry("key2", "value 2").unwrap();

    let value_1 = database.read_entry(index_1).unwrap();
    let value_2 = database.read_entry(index_2).unwrap();

    assert_eq!(value_1, ("key1".to_string(), b"this is a value".to_vec()));
    assert_eq!(value_2, ("key2".to_string(), b"value 2".to_vec()));

    assert!(database.read_entry(1234).is_err());

    drop(database);
    fs::remove_file("test_read_write.jdb").unwrap();
}

#[test]
fn load_indexes() {
    let mut database = FileSource::new("test_load_indexes.jdb").unwrap();

    database.write_entry("key1", "this is a value").unwrap();
    let index_2 = database.write_entry("key2", "value 2").unwrap();
    let index_3 = database.write_entry("key1", "overwritten!").unwrap();
    database.write_entry("key3", "not null").unwrap();
    database.write_entry("key3", "null").unwrap();

    let indexes = database.load_indexes().unwrap();

    assert_eq!(indexes.len(), 2);
    assert_eq!(indexes["key1"], index_3);
    assert_eq!(indexes["key2"], index_2);

    drop(database);
    fs::remove_file("test_load_indexes.jdb").unwrap();
}

#[test]
fn compact() {
    let mut database = FileSource::new("test_compact.jdb").unwrap();

    database.write_entry("key1", "this is a value").unwrap();
    database.write_entry("key2", "value 2").unwrap();
    database.write_entry("key1", "overwritten!").unwrap();
    database.write_entry("key3", "not null").unwrap();
    database.write_entry("key3", "null").unwrap();

    let indexes = database.load_indexes().unwrap();

    database.compact(&indexes).unwrap();

    let mut buf: Vec<u8> = vec![0; database.len as usize];
    database.file.rewind().unwrap();
    database.file.read_exact(&mut buf).unwrap();
    assert!(
        buf == b"\x04\0\0\0\0\0\0\0key2\x07\0\0\0\0\0\0\0value 2\x04\0\0\0\0\0\0\0key1\x0c\0\0\0\0\0\0\0overwritten!" ||
        buf == b"\x04\0\0\0\0\0\0\0key1\x0c\0\0\0\0\0\0\0overwritten!\x04\0\0\0\0\0\0\0key2\x07\0\0\0\0\0\0\0value 2"
    );

    drop(database);
    fs::remove_file("test_compact.jdb").unwrap();
}

#[test]
fn open_existing() {
    {
        let mut file = File::create("test_open_existing.jdb").unwrap();
        file.write_all(b"\x04\0\0\0\0\0\0\0key2\x07\0\0\0\0\0\0\0value 2\x04\0\0\0\0\0\0\0key1\x0c\0\0\0\0\0\0\0overwritten!").unwrap();
    }

    let mut database = FileSource::new("test_open_existing.jdb").unwrap();

    let value_1 = database.read_entry(0).unwrap();
    let value_2 = database.read_entry(27).unwrap();

    assert_eq!(value_1, ("key2".to_string(), b"value 2".to_vec()));
    assert_eq!(value_2, ("key1".to_string(), b"overwritten!".to_vec()));

    drop(database);
    fs::remove_file("test_open_existing.jdb").unwrap();
}

#[test]
fn index_on() -> Result<(), Box<dyn std::error::Error>> {
    let mut database = FileSource::new("test_index_on.jdb")?;

    let elizabeth_ii = database.write_entry(
        "elizabeth_ii",
        json!({"name": "Elizabeth II", "year_of_birth": 1926, "gender": "female"}).serialize(),
    )?;

    let george_vi = database.write_entry(
        "george_vi",
        json!({"name": "George VI", "year_of_birth": 1895, "gender": "male"}).serialize(),
    )?;

    let edward_viii = database.write_entry(
        "edward_viii",
        json!({"name": "Edward VIII", "year_of_birth": 1894, "gender": "male"}).serialize(),
    )?;

    let indexes = database.load_indexes()?;
    let index_on_gender = database.index_on("gender", &indexes)?;
    let index_on_year = database.index_on("year_of_birth", &indexes)?;

    let men = index_on_gender.get(&json!("male")).unwrap();
    assert_eq!(men.len(), 2);
    assert!(men.contains(&george_vi));
    assert!(men.contains(&edward_viii));
    assert!(!men.contains(&elizabeth_ii));

    let women = index_on_gender.get(&json!("female")).unwrap();
    assert_eq!(*women, [elizabeth_ii].iter().cloned().collect());

    let born_in_1895 = index_on_year.get(&json!(1895)).unwrap();
    assert_eq!(*born_in_1895, [george_vi].iter().cloned().collect());

    let born_in_1900 = index_on_year.get(&json!(1900));
    assert!(born_in_1900.is_none());

    drop(database);
    fs::remove_file("test_index_on.jdb").unwrap();

    Ok(())
}