1
//! An example on how to use `nebari::tree`, the low-level single-tree database
2
//! layer. For most users, the `nebari::Roots` type should be preferred.
3

            
4
use nebari::{
5
    io::{fs::StdFile, memory::MemoryFile, ManagedFile},
6
    tree::{ScanEvaluation, State, TreeFile, Unversioned, Versioned},
7
    ArcBytes, Context, Error,
8
};
9

            
10
fn main() -> Result<(), Error> {
11
    // At its core, Nebari operates on TreeFiles. Each TreeFile is defined by
12
    // its Root -- the two Roots included with Nebari are the VersionedTreeRoot
13
    // and UnversionedTreeRoot. As you may guess from their names, the different
14
    // tree roots control whether full revision information is stored.
15
    //
16
    // To begin, let's open up a file without versioning on the filesystem:
17
    let mut unversioned_tree = TreeFile::<Unversioned, StdFile>::write(
18
        "unversioned-tree.nebari",
19
        State::default(),
20
        &Context::default(),
21
        None,
22
    )?;
23

            
24
    // We can use this filesystem-backed tree to do common tree operations.
25
    tree_basics(&mut unversioned_tree)?;
26

            
27
    // Or we could do the same thing, but this time using a memory-backed file.
28
    // Note: this isn't recommended to be used in production, but it can be
29
    // helpful in CI environments.
30
    let mut unversioned_memory_tree = TreeFile::<Unversioned, MemoryFile>::write(
31
        "unversioned-tree.nebari",
32
        State::default(),
33
        &Context::default(),
34
        None,
35
    )?;
36
    tree_basics(&mut unversioned_memory_tree)?;
37

            
38
    // We can also use the VersionedTreeRoot to be able to view full revision history in a tree.
39
    let mut versioned_tree = TreeFile::<Versioned, StdFile>::write(
40
        "versioned-tree.nebari",
41
        State::default(),
42
        &Context::default(),
43
        None,
44
    )?;
45
    tree_basics(&mut versioned_tree)?;
46

            
47
    versioned_tree.scan_sequences(
48
        ..,
49
        true,
50
        false,
51
        |_key| ScanEvaluation::ReadData,
52
        |key, data| {
53
            println!(
54
                "Key {:?} contained {:?} at sequence {:?}. Previous sequence: {:?}",
55
                key.key, data, key.sequence, key.last_sequence
56
            );
57
            Ok(())
58
        },
59
    )?;
60

            
61
    Ok(())
62
}
63

            
64
fn tree_basics<Root: nebari::tree::Root<Value = ArcBytes<'static>>, File: ManagedFile>(
65
    tree: &mut TreeFile<Root, File>,
66
) -> Result<(), Error> {
67
    // Insert a few key-value pairs.
68
    tree.set(None, ArcBytes::from(b"a key"), ArcBytes::from(b"a value"))?;
69
    tree.set(None, ArcBytes::from(b"b key"), ArcBytes::from(b"b value"))?;
70
    // Retrieve a value.
71
    let value = tree.get(b"a key", false)?.unwrap();
72
    assert_eq!(value, b"a value");
73

            
74
    // Scan for values
75
    tree.scan(
76
        &(..),
77
        true,
78
        false,
79
        |_, _, _| ScanEvaluation::ReadData,
80
        |_key, _index| ScanEvaluation::ReadData,
81
        |key, _index, value| {
82
            println!("Found key {:?} with value {:?}", key, value);
83
            Ok(())
84
        },
85
    )?;
86

            
87
    // Replace the value for "a key"
88
    tree.set(
89
        None,
90
        ArcBytes::from(b"a key"),
91
        ArcBytes::from(b"a new value"),
92
    )?;
93
    let updated_value = tree.get(b"a key", false)?.unwrap();
94
    assert_eq!(updated_value, b"a new value");
95

            
96
    Ok(())
97
}