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

            
7
2
#[derive(Debug, Schema)]
8
#[schema(name = "primary-keys", collections = [UserProfile, AssociatedProfileData])]
9
struct ExampleSchema;
10

            
11
// ANCHOR: derive_with_natural_id
12
7
#[derive(Debug, Serialize, Deserialize, Collection, Eq, PartialEq)]
13
#[collection(name = "user-profiles", primary_key = u32)]
14
struct UserProfile {
15
    #[natural_id]
16
    pub external_id: u32,
17
    pub name: String,
18
}
19
// ANCHOR_END: derive_with_natural_id
20

            
21
// ANCHOR: derive
22
8
#[derive(Debug, Serialize, Deserialize, Collection, Eq, PartialEq)]
23
#[collection(name = "multi-key", primary_key = AssociatedProfileKey)]
24
struct AssociatedProfileData {
25
    value: String,
26
}
27

            
28
5
#[derive(Key, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
29
struct AssociatedProfileKey {
30
    pub user_id: u32,
31
    pub data_id: u64,
32
}
33
// ANCHOR_END: derive
34

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

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

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

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

            
85
1
    Ok(())
86
1
}
87

            
88
1
#[test]
89
1
fn runs() {
90
1
    main().unwrap()
91
1
}