1
1
use bonsaidb::{
2
    core::{
3
        key::NextValueError,
4
        schema::{Collection, Schema, SerializedCollection},
5
    },
6
    local::{
7
        config::{Builder, StorageConfiguration},
8
        Database,
9
    },
10
};
11
use serde::{Deserialize, Serialize};
12

            
13
2
#[derive(Debug, Schema)]
14
#[schema(name = "primary-keys", collections = [UserProfile, MultiKey])]
15
struct ExampleSchema;
16

            
17
// ANCHOR: derive_with_natural_id
18
7
#[derive(Debug, Serialize, Deserialize, Collection, Eq, PartialEq)]
19
1
#[collection(name = "user-profiles", primary_key = u32, natural_id = |user: &UserProfile| Some(user.external_id))]
20
struct UserProfile {
21
    pub external_id: u32,
22
    pub name: String,
23
}
24
// ANCHOR_END: derive_with_natural_id
25

            
26
// ANCHOR: derive
27
8
#[derive(Debug, Serialize, Deserialize, Collection, Eq, PartialEq)]
28
#[collection(name = "multi-key", primary_key = (u32, u64))]
29
struct MultiKey {
30
    value: String,
31
}
32
// ANCHOR_END: derive
33

            
34
1
fn main() -> Result<(), bonsaidb::core::Error> {
35
1
    drop(std::fs::remove_dir_all("primary-keys.bonsaidb"));
36
1
    let db = Database::open::<ExampleSchema>(StorageConfiguration::new("primary-keys.bonsaidb"))?;
37

            
38
    // It's not uncommon to need to store data in a database that has an
39
    // "external" identifier. Some examples could be externally authenticated
40
    // user profiles, social networking site posts, or for normalizing a single
41
    // type's fields across multiple Collections.
42
    //
43
    // The UserProfile type in this example has a `u32` primary key, and it
44
    // defines a closure that returns the field `external_id`. When pushing a
45
    // value into a collection with a natural id, it will automatically become
46
    // the primary key:
47
    // ANCHOR: natural_id_query
48
1
    let user = UserProfile {
49
1
        external_id: 42,
50
1
        name: String::from("ecton"),
51
1
    }
52
1
    .push_into(&db)?;
53
1
    let retrieved_from_database = UserProfile::get(42, &db)?.expect("document not found");
54
1
    assert_eq!(user, retrieved_from_database);
55
    // ANCHOR_END: natural_id_query
56

            
57
    // It's possible to use any type that implements the Key trait as a primary
58
    // key, including tuples:
59
    // ANCHOR: query
60
1
    let inserted = MultiKey {
61
1
        value: String::from("hello"),
62
1
    }
63
1
    .insert_into((42, 64), &db)?;
64
1
    let retrieved = MultiKey::get((42, 64), &db)?.expect("document not found");
65
1
    assert_eq!(inserted, retrieved);
66
    // ANCHOR_END: query
67

            
68
    // Not all primary key types support automatic key assignment -- the Key
69
    // trait implementation controls that behavior:
70
1
    assert!(matches!(
71
1
        MultiKey {
72
1
            value: String::from("error"),
73
1
        }
74
1
        .push_into(&db)
75
1
        .unwrap_err()
76
        .error,
77
        bonsaidb::core::Error::DocumentPush(_, NextValueError::Unsupported)
78
    ));
79
1
    Ok(())
80
1
}
81

            
82
1
#[test]
83
1
fn runs() {
84
1
    main().unwrap()
85
1
}