gosh_database/
collection.rs1use crate::schema::*;
2use crate::*;
3
4use gut::prelude::*;
5
6pub trait Collection
7where
8 Self: serde::Serialize + serde::de::DeserializeOwned,
9{
10 fn collection_name() -> String {
12 format!("{}.ckpt", std::any::type_name::<Self>())
13 }
14
15 fn put_into_collection(&self, db: &DbConnection, new_key: &str) -> Result<()> {
19 use crate::schema::kvstore::dsl::*;
20
21 let conn = db.get();
22 let cname = &Self::collection_name();
23
24 let row = (
25 collection.eq(cname),
26 key.eq(new_key),
27 data.eq(bincode::serialize(&self).unwrap()),
28 );
29
30 diesel::replace_into(kvstore)
31 .values(&row)
32 .execute(&*conn)
33 .with_context(|| {
34 format!(
35 "Failed to put data into collection {} with key {}\n db source: {}",
36 cname,
37 new_key,
38 db.database_url()
39 )
40 })?;
41
42 Ok(())
43 }
44
45 fn get_from_collection(db: &DbConnection, obj_key: &str) -> Result<Self> {
47 use crate::schema::kvstore::dsl::*;
48
49 let conn = db.get();
50 let cname = &Self::collection_name();
51 let encoded: Vec<u8> = kvstore
52 .filter(collection.eq(&cname))
53 .filter(key.eq(&obj_key))
54 .select(data)
55 .first(&*conn)?;
56
57 let x = bincode::deserialize(&encoded)
58 .with_context(|| format!("Failed to deserialize data for {}/{}", cname, obj_key))?;
59
60 Ok(x)
61 }
62
63 fn del_from_collection(db: &DbConnection, obj_key: &str) -> Result<()> {
65 use crate::schema::kvstore::dsl::*;
66
67 let conn = db.get();
68 let cname = &Self::collection_name();
69 diesel::delete(kvstore.filter(collection.eq(&cname)).filter(key.eq(&obj_key))).execute(&*conn)?;
70
71 Ok(())
72 }
73
74 fn remove_collection(db: &DbConnection) -> Result<()> {
76 use crate::schema::kvstore::dsl::*;
77
78 let conn = db.get();
79 let cname = &Self::collection_name();
80 diesel::delete(kvstore.filter(collection.eq(&cname))).execute(&*conn)?;
81 Ok(())
82 }
83
84 fn list_collection(db: &DbConnection) -> Result<Vec<Self>> {
86 use crate::schema::kvstore::dsl::*;
87
88 let conn = db.get();
89 let cname = &Self::collection_name();
90 let list: Vec<(String, Vec<u8>)> = kvstore.filter(collection.eq(&cname)).select((key, data)).load(&*conn)?;
91
92 let mut items = vec![];
93 for (obj_key, encoded) in list {
94 let x = bincode::deserialize(&encoded)
95 .with_context(|| format!("Failed to deserialize data for {}/{}", cname, obj_key))?;
96 items.push(x);
97 }
98 Ok(items)
99 }
100
101 fn collection_size(db: &DbConnection) -> Result<i64> {
103 use crate::schema::kvstore::dsl::*;
104
105 let conn = db.get();
106 let cname = &Self::collection_name();
107 let count = kvstore.filter(collection.eq(&cname)).count().get_result(&*conn)?;
108
109 Ok(count)
113 }
114}
115
116impl<T> Collection for T where T: serde::Serialize + serde::de::DeserializeOwned {}
117
118#[cfg(test)]
119mod test {
120 use super::*;
121
122 #[derive(Clone, Debug, Serialize, Deserialize)]
123 struct TestObject {
124 data: f64,
125 }
126
127 #[test]
128 fn test_collection() -> Result<()> {
129 let tdir = tempfile::tempdir()?;
131 let tmpdb = tdir.path().join("test.sqlite");
132 let url = format!("{}", tmpdb.display());
133 let db = DbConnection::connect(&url)?;
134
135 let x = TestObject { data: -12.0 };
136 x.put_into_collection(&db, "test1")?;
137
138 TestObject::get_from_collection(&db, "test1")?;
139
140 TestObject::del_from_collection(&db, "test1")?;
141
142 TestObject::remove_collection(&db)?;
143
144 let x = TestObject::list_collection(&db)?;
145 assert!(x.is_empty());
146
147 let x = TestObject { data: 12.0 };
148 x.put_into_collection(&db, "test1")?;
149 let x = TestObject::list_collection(&db)?;
150 assert_eq!(1, x.len());
151
152 let x = TestObject { data: -12.0 };
153 x.put_into_collection(&db, "test1")?;
154 let x_new = TestObject::get_from_collection(&db, "test1")?;
155 assert_eq!(x.data, x_new.data);
156
157 Ok(())
158 }
159}