pack_db/
lib.rs

1///! # PackDb
2///! PackDb is a simple key value messagepack store
3///! Inspired by [kwik](https://deno.land/x/kwik/)
4///! It uses your local storage
5///! ## Example
6/// ```rs
7/// use pack_db::PackDb:
8/// use serde::{Deserialize, Serialize};
9///
10/// #[derive(Debug, PartialEq, Deserialize, Serialize)]
11/// struct User {
12///     name: String,
13///     age: i32
14/// }
15///
16/// let store = PackDb::<User>::new(Some("data".to_owned()));
17/// store.set("user1", User {name: "useer1", age: 16});
18/// let user = store.get("user1");
19///```
20use anyhow::Result;
21use rmp_serde::Serializer;
22use serde::de::DeserializeOwned;
23// It is actually being used (?)
24#[allow(unused_imports)]
25use serde::{Deserialize, Serialize};
26use std::collections::HashMap;
27use std::fs::{create_dir_all, metadata, read, read_dir, remove_dir, remove_file, write};
28
29pub struct PackDb<T: DeserializeOwned + Serialize> {
30    store: String,
31    //Yeah idk how to do this in a better way sorry everyone!
32    #[allow(dead_code)]
33    a: Option<T>,
34}
35impl<T: DeserializeOwned + Serialize> PackDb<T> {
36    //Create a new store
37    pub fn new(store: Option<String>) -> Self {
38        let loc = store.unwrap_or_else(|| "data".into());
39        create_dir_all(&loc).unwrap();
40        PackDb::<T> {
41            store: loc,
42            a: None,
43        }
44    }
45    fn path<K: std::fmt::Display>(&self, key: K) -> String {
46        format!("{}/{}.pak", &self.store, key)
47    }
48    /// Check if a item exists
49    pub fn has<K: std::fmt::Display>(&self, key: K) -> bool {
50        let exists = metadata(self.path(key));
51        exists.is_ok()
52    }
53    /// Set a item
54    pub fn set<K: std::fmt::Display>(&self, key: K, val: T) -> Result<()> {
55        let mut buf = vec![];
56        val.serialize(&mut Serializer::new(&mut buf))?;
57        write(self.path(key), buf)?;
58        Ok(())
59    }
60    /// Get a key
61    pub fn get<K: std::fmt::Display>(&self, key: K) -> Result<T> {
62        let r = read(self.path(key))?;
63        Ok(rmp_serde::from_read_ref(&r)?)
64    }
65
66    /// Receive every object in the store
67    pub fn get_all(&self) -> Result<HashMap<String, T>> {
68        let mut res = HashMap::new();
69        let entries = read_dir(&self.store)?;
70
71        for entry in entries.flatten() {
72            let name = entry.file_name().to_string_lossy().replace(".pak", "");
73            res.insert(name.clone(), self.get(&name)?);
74        }
75
76        Ok(res)
77    }
78    /// List all keys
79    pub fn keys(&self) -> Result<Vec<String>> {
80        let mut res = vec![];
81        let entries = read_dir(&self.store)?;
82        for entry in entries.flatten() {
83            let name = entry.file_name().to_string_lossy().replace(".pak", "");
84            res.push(name);
85        }
86        Ok(res)
87    }
88    /// returns the number of elements in the store
89    pub fn len(&self) -> Result<usize> {
90        let entries = read_dir(&self.store)?;
91        Ok(entries.flatten().count())
92    }
93
94    /// Checks if the store is empty
95    pub fn is_empty(&self) -> Result<bool> {
96        Ok(self.len()? == 0)
97    }
98
99    /// Insert a hashmap of values all at once
100    pub fn insert_many<K: std::fmt::Display>(&self, data: HashMap<K, T>) -> Result<bool> {
101        for (key, val) in data {
102            self.set(key, val)?;
103        }
104        Ok(true)
105    }
106
107    ///Delete a key - this deletes the file from the file system
108    pub fn delete<K: std::fmt::Display>(&self, key: K) -> bool {
109        let exists = remove_file(self.path(key));
110        exists.is_ok()
111    }
112
113    /// Empty the storage this deletes all keys from the storage
114    pub fn clear(&self) -> Result<bool> {
115        remove_dir(&self.store)?;
116        create_dir_all(&self.store)?;
117        Ok(true)
118    }
119
120    /// Clears the store, returning all key-value pairs as an HasMap
121    pub fn drain(&self) -> Result<HashMap<String, T>> {
122        let data = self.get_all();
123        self.clear()?;
124        data
125    }
126}
127
128#[cfg(test)]
129mod test {
130    #[derive(Debug, PartialEq, Deserialize, Serialize)]
131    struct Human {
132        age: u32,
133        name: String,
134    }
135
136    use super::*;
137    #[test]
138    fn test() -> Result<()> {
139        let storage = PackDb::<Human>::new(Some("store".to_owned()));
140
141        storage.set(
142            "testing",
143            Human {
144                age: 22,
145                name: "this is a test".into(),
146            },
147        )?;
148
149        let user = storage.get("testing")?;
150
151        assert_eq!(user.name, "this is a test".to_owned());
152
153        let users = storage.get_all()?;
154        let _user = users.get("testing").unwrap();
155
156        assert_eq!(storage.has("testing"), true);
157        assert_eq!(storage.delete("testing"), true);
158        assert_eq!(storage.has("testing"), false);
159        Ok(())
160    }
161}