devjournal 0.1.0

A dev first cli journaling tool
Documentation
use crate::domain::journal::Journal;
use crate::persistence::journal_record::JournalRecord;
use crate::repositories::repository::Repository;
use crate::store::store;

use anyhow::Result;
use std::{
    collections::HashMap,
    fs,
    path::{Path, PathBuf},
};
use uuid::Uuid;

pub struct JournalRepository {
    store_path: PathBuf,
}

impl JournalRepository {
    pub fn new<P: AsRef<Path>>(path: P) -> Self {
        Self {
            store_path: path.as_ref().to_path_buf(),
        }
    }

    fn ensure_store_dir(&self) -> std::io::Result<()> {
        if let Some(parent) = self.store_path.parent() {
            fs::create_dir_all(parent)?;
        }
        Ok(())
    }
}

impl Repository<Journal> for JournalRepository {
    fn add(&self, journal: &Journal) -> Result<()> {
        let mut journals: HashMap<Uuid, JournalRecord> = if self.store_path.exists() {
            store::read_json(&self.store_path)?
        } else {
            HashMap::new()
        };

        journals.insert(journal.id, journal.into());

        self.ensure_store_dir()?;
        store::save_json(&self.store_path, &journals)?;
        Ok(())
    }

    fn get(&self, id: &Uuid) -> Result<Option<Journal>> {
        if !self.store_path.exists() {
            return Ok(None);
        }

        let journals: HashMap<Uuid, JournalRecord> = store::read_json(&self.store_path)?;
        Ok(journals.get(id).map(|journal| journal.into()))
    }

    fn get_by_name(&self, name: &String) -> Result<Option<Journal>> {
        if !self.store_path.exists() {
            return Ok(None);
        }

        let journals: HashMap<Uuid, JournalRecord> = store::read_json(&self.store_path)?;
        let journals_by_name_map: HashMap<String, JournalRecord> = journals
            .into_iter()
            .map(|(_, journal)| (journal.name.clone(), journal))
            .collect();

        Ok(journals_by_name_map.get(name).map(|journal| journal.into()))
    }

    fn update(&self, journal: &Journal) -> Result<()> {
        let mut journals: HashMap<Uuid, JournalRecord> = if self.store_path.exists() {
            store::read_json(&self.store_path)?
        } else {
            HashMap::new()
        };

        // Replace existing journal or insert new one
        journals.insert(journal.id, journal.into());

        self.ensure_store_dir()?;
        store::save_json(&self.store_path, &journals)?;
        Ok(())
    }
}