1
1
use bonsaidb::{
2
    core::{
3
        connection::Connection,
4
        document::{CollectionDocument, Emit},
5
        schema::{
6
            view::CollectionViewSchema, Collection, ReduceResult, SerializedCollection, View,
7
            ViewMapResult, ViewMappedValue,
8
        },
9
    },
10
    local::{
11
        config::{Builder, StorageConfiguration},
12
        Database,
13
    },
14
};
15
use serde::{Deserialize, Serialize};
16

            
17
// begin rustme snippet: snippet-a
18
72
#[derive(Debug, Serialize, Deserialize, Collection)]
19
#[collection(name = "shapes", views = [ShapesByNumberOfSides])]
20
struct Shape {
21
    pub sides: u32,
22
}
23

            
24
74
#[derive(Debug, Clone, View)]
25
#[view(collection = Shape, key = u32, value = usize, name = "by-number-of-sides")]
26
struct ShapesByNumberOfSides;
27

            
28
impl CollectionViewSchema for ShapesByNumberOfSides {
29
    type View = Self;
30

            
31
21
    fn map(&self, document: CollectionDocument<Shape>) -> ViewMapResult<Self::View> {
32
21
        document
33
21
            .header
34
21
            .emit_key_and_value(document.contents.sides, 1)
35
21
    }
36

            
37
20
    fn reduce(
38
20
        &self,
39
20
        mappings: &[ViewMappedValue<Self>],
40
20
        _rereduce: bool,
41
20
    ) -> ReduceResult<Self::View> {
42
33
        Ok(mappings.iter().map(|m| m.value).sum())
43
20
    }
44
}
45
// end rustme snippet
46

            
47
1
fn main() -> Result<(), bonsaidb::core::Error> {
48
    // begin rustme snippet: snippet-b
49
1
    let db = Database::open::<Shape>(StorageConfiguration::new("view-examples.bonsaidb"))?;
50

            
51
    // Insert a new document into the Shape collection.
52
1
    Shape { sides: 3 }.push_into(&db)?;
53
    // end rustme snippet
54

            
55
    // Views in BonsaiDb are written using a Map/Reduce approach. In this
56
    // example, we take a look at how document mapping can be used to filter and
57
    // retrieve data
58
    //
59
    // Let's start by seeding the database with some shapes of various sizes:
60
19
    for sides in 3..=20 {
61
18
        Shape { sides }.push_into(&db)?;
62
    }
63

            
64
    // And, let's add a few shapes with the same number of sides
65
1
    Shape { sides: 3 }.push_into(&db)?;
66
1
    Shape { sides: 4 }.push_into(&db)?;
67

            
68
    // At this point, our database should have 3 triangles:
69
    // begin rustme snippet: snippet-c
70
1
    let triangles = db.view::<ShapesByNumberOfSides>().with_key(3).query()?;
71
1
    println!("Number of triangles: {}", triangles.len());
72
1
    // end rustme snippet
73
1

            
74
1
    // What is returned is a list of entries containing the document id
75
1
    // (source), the key of the entry, and the value of the entry:
76
1
    println!("Triangles: {:#?}", triangles);
77

            
78
    // If you want the associated documents, use query_with_collection_docs:
79
3
    for entry in &db
80
1
        .view::<ShapesByNumberOfSides>()
81
1
        .with_key(3)
82
1
        .query_with_collection_docs()?
83
3
    {
84
3
        println!(
85
3
            "Shape ID {} has {} sides",
86
3
            entry.document.header.id, entry.document.contents.sides
87
3
        );
88
3
    }
89

            
90
    // The reduce() function takes the "values" emitted during the map()
91
    // function, and reduces a list down to a single value. In this example, the
92
    // reduce function is acting as a count. So, if you want to query for the
93
    // number of shapes, we don't need to fetch all the records, we can just
94
    // retrieve the result of the calculation directly.
95
    //
96
    // So, here we're using reduce() to count the number of shapes with 4 sides.
97
1
    println!(
98
1
        "Number of quads: {} (expected 2)",
99
1
        db.view::<ShapesByNumberOfSides>().with_key(4).reduce()?
100
    );
101

            
102
    // Or, 5 shapes that are triangles or quads
103
1
    println!(
104
1
        "Number of quads and triangles: {} (expected 5)",
105
1
        db.view::<ShapesByNumberOfSides>()
106
1
            .with_keys([3, 4])
107
1
            .reduce()?
108
    );
109

            
110
    // And, 10 shapes that have more than 10 sides
111
1
    println!(
112
1
        "Number of shapes with more than 10 sides: {} (expected 10)",
113
1
        db.view::<ShapesByNumberOfSides>()
114
1
            .with_key_range(11..u32::MAX)
115
1
            .reduce()?
116
    );
117

            
118
1
    Ok(())
119
1
}
120

            
121
1
#[test]
122
1
fn runs() {
123
1
    drop(std::fs::remove_dir_all("view-examples.bonsaidb"));
124
1
    main().unwrap()
125
1
}