database done + popup start

This commit is contained in:
maxstrb 2025-09-14 12:13:04 +02:00
commit 234b17a8b0
12 changed files with 1134 additions and 0 deletions

156
src/database.rs Normal file
View file

@ -0,0 +1,156 @@
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(())
}
}