156 lines
4.5 KiB
Rust
156 lines
4.5 KiB
Rust
use std::collections::hash_map::DefaultHasher;
|
|
use std::hash::{Hash, Hasher};
|
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
use std::{env::home_dir, fs};
|
|
|
|
use crate::day_info::{DayInfo, Event};
|
|
use chrono::NaiveDate;
|
|
use redb::{Database, Error, ReadableDatabase, ReadableTable, TableDefinition};
|
|
|
|
const MAIN_TABLE: TableDefinition<NaiveDate, Vec<(u64, String)>> = TableDefinition::new("main"); // Vec<tag_id, event_description>
|
|
const TAG_TABLE: TableDefinition<u64, String> = TableDefinition::new("tags");
|
|
|
|
pub struct DB {
|
|
db: Database,
|
|
}
|
|
|
|
impl DB {
|
|
pub fn new() -> Result<Self, Error> {
|
|
let mut path = home_dir().ok_or(Error::DatabaseAlreadyOpen)?;
|
|
path.push(".local/share/cars");
|
|
|
|
fs::create_dir_all(&path)?;
|
|
|
|
path.push("main.redb");
|
|
let db = Database::create(path)?;
|
|
|
|
let write_txn = db.begin_write()?;
|
|
|
|
{
|
|
let _main_table = write_txn.open_table(MAIN_TABLE)?;
|
|
let _tag_table = write_txn.open_table(TAG_TABLE)?;
|
|
}
|
|
|
|
write_txn.commit()?;
|
|
|
|
Ok(Self { db })
|
|
}
|
|
|
|
pub fn get_day(&self, day: NaiveDate) -> Result<Option<DayInfo>, Error> {
|
|
match self.db.begin_read()?.open_table(MAIN_TABLE)?.get(day)? {
|
|
None => Ok(None),
|
|
Some(data) => {
|
|
let events = data.value();
|
|
let mut output = DayInfo::default();
|
|
|
|
for (tag_id, event_description) in events {
|
|
let tag_name = self.db.begin_read()?.open_table(TAG_TABLE)?.get(tag_id)?;
|
|
output.events.push(match tag_name {
|
|
Some(_name) => Event::new(Some(tag_id), event_description),
|
|
|
|
None => Event::new(None, event_description),
|
|
});
|
|
}
|
|
|
|
Ok(Some(output))
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn add_event(&mut self, day: NaiveDate, event: Event) -> Result<(), Error> {
|
|
let mut new_vec = match self.db.begin_read()?.open_table(MAIN_TABLE)?.get(day)? {
|
|
Some(d) => d.value(),
|
|
None => vec![],
|
|
};
|
|
|
|
new_vec.push((
|
|
event.tag.expect("You should pass a valid event"),
|
|
event.description,
|
|
));
|
|
|
|
let write_txn = self.db.begin_write()?;
|
|
{
|
|
let mut table = write_txn.open_table(MAIN_TABLE)?;
|
|
table.insert(day, new_vec)?;
|
|
}
|
|
write_txn.commit()?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn remove_event(&mut self, day: NaiveDate, index: usize) -> Result<(), Error> {
|
|
let mut old_vec = match self.db.begin_read()?.open_table(MAIN_TABLE)?.get(day)? {
|
|
Some(d) => d.value(),
|
|
None => vec![],
|
|
};
|
|
|
|
if old_vec.len() <= index {
|
|
return Ok(());
|
|
}
|
|
|
|
old_vec.remove(index);
|
|
|
|
let write_txn = self.db.begin_write()?;
|
|
{
|
|
let mut table = write_txn.open_table(MAIN_TABLE)?;
|
|
table.insert(day, old_vec)?;
|
|
}
|
|
write_txn.commit()?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn get_tags(&self) -> Result<Vec<(u64, String)>, Error> {
|
|
self.db
|
|
.begin_read()?
|
|
.open_table(TAG_TABLE)?
|
|
.iter()?
|
|
.map(|x| -> Result<(u64, String), Error> {
|
|
let val = x?;
|
|
Ok((val.0.value(), val.1.value()))
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
pub fn get_tag_name(&self, id: u64) -> Result<Option<String>, Error> {
|
|
match self.db.begin_read()?.open_table(TAG_TABLE)?.get(id)? {
|
|
Some(name) => Ok(Some(name.value())),
|
|
None => Ok(None),
|
|
}
|
|
}
|
|
|
|
pub fn create_tag(&mut self, tag_name: String) -> Result<u64, Error> {
|
|
let now = SystemTime::now()
|
|
.duration_since(UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_nanos() as u64;
|
|
|
|
let mut hasher = DefaultHasher::new();
|
|
tag_name.hash(&mut hasher);
|
|
let tag_hash = hasher.finish();
|
|
|
|
let tag_id = now.wrapping_add(tag_hash);
|
|
|
|
let write_txn = self.db.begin_write()?;
|
|
{
|
|
let mut tag_table = write_txn.open_table(TAG_TABLE)?;
|
|
tag_table.insert(tag_id, tag_name)?;
|
|
}
|
|
write_txn.commit()?;
|
|
|
|
std::thread::sleep(std::time::Duration::from_micros(1));
|
|
|
|
Ok(tag_id)
|
|
}
|
|
|
|
pub fn delete_tag(&mut self, tag_id: u64) -> Result<(), Error> {
|
|
let write_txn = self.db.begin_write()?;
|
|
{
|
|
let mut table = write_txn.open_table(TAG_TABLE)?;
|
|
table.remove(tag_id)?;
|
|
}
|
|
write_txn.commit()?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|