use crate::error::Result; use std::path::Path; use geoffrey_models::GeoffreyDatabaseModel; use crate::{u64_from_bytes, u64_to_bytes}; use sled::Iter; pub struct Database { db: sled::Db, } impl Database { pub fn new(db_path: &Path) -> Result { let db = sled::open(db_path)?; Ok(Self { db, }) } fn get_tree(&self) -> Result where T: GeoffreyDatabaseModel { Ok(self.db.open_tree::(T::tree())?) } pub fn insert(&self, mut model: T) -> Result where T: GeoffreyDatabaseModel { let id = match model.id() { Some(id) => id, None => { let id = self.db.generate_id()?; model.set_id(id); id } }; let tree = self.get_tree::()?; let id_bytes = u64_to_bytes(id); tree.insert(id_bytes, model.to_bytes()?)?; Ok(model) } pub fn get(&self, id: u64) -> Result> where T: GeoffreyDatabaseModel { let tree = self.get_tree::()?; let id_bytes = u64_to_bytes(id); if let Some(bytes) = tree.get(id_bytes)? { Ok(Some(T::try_from_bytes(&bytes)?)) } else { Ok(None) } } pub fn filter(&self, f: F) -> Result> where T: GeoffreyDatabaseModel, F: Fn(u64, &T) -> bool { let tree = self.db.open_tree(T::tree())?; Ok(tree.iter().filter_map(|e| { if let Ok((id, data)) = e { let id = u64_from_bytes(&mut id.clone()); let data = T::try_from_bytes(&data).unwrap(); if f(id, &data) { Some(data) } else { None } } else { None } }).collect()) } pub fn tree_iter(&self) -> Result where T: GeoffreyDatabaseModel { Ok(self.db.open_tree(T::tree()).map(|tree| tree.iter())?) } } #[cfg(test)] mod tests { use crate::database::{Database}; use std::path::Path; use geoffrey_models::models::player::{Player, UserID}; use lazy_static::lazy_static; use geoffrey_models::GeoffreyDatabaseModel; lazy_static! { static ref DB: Database = Database::new(Path::new("../locations")).unwrap(); } fn cleanup() { DB.db.clear().unwrap(); } #[test] fn test_insert() { let player = Player::new("CoolZero123", UserID::DiscordUUID(0u64)); let p2 = DB.insert::(player.clone()).unwrap(); assert!(p2.id().is_some()); assert_eq!(player.name, p2.name); cleanup(); } #[test] fn test_get() { let player = Player::new("CoolZero123", UserID::DiscordUUID(0u64)); let p2 = DB.insert::(player.clone()).unwrap(); let p3 = DB.get::(p2.id().unwrap()).unwrap(); assert!(p3.is_some()); assert_eq!(p3.unwrap().name, player.name); cleanup(); } }