use std::fs::File; use std::io::Write; use crate::domain; use crate::repo::{Error, InsertTaskData, Repository}; use serde::{Deserialize, Serialize}; use xdg::BaseDirectories; #[derive(Deserialize, Serialize, Clone)] pub struct Task { name: String, link: Option, // created_at } impl From for domain::Task { fn from(repo: Task) -> Self { domain::Task { name: repo.name, link: repo.link, } } } const DATA_FILE: &str = "data.json"; pub struct FsRepo { xdg_dirs: BaseDirectories, } impl FsRepo { pub fn new(xdg_dirs: BaseDirectories) -> Self { Self { xdg_dirs } } } impl Repository for FsRepo { fn get_tasks(&self) -> Result, Error> { self.get_tasks_impl() .map(|tasks| tasks.into_iter().map(Task::into).collect()) } fn insert_task(&self, insert_data: InsertTaskData) -> Result { let new_task = Task { name: insert_data.name, link: insert_data.link, }; let mut tasks = self.get_tasks_impl()?; tasks.push(new_task.clone()); let file_path = self .xdg_dirs .place_data_file(DATA_FILE) .map_err(|_| Error::InsertData)?; let mut file = File::create(&file_path).map_err(|_| Error::InsertData)?; let new_data = serde_json::to_vec(&tasks).map_err(|_| Error::InvalidData)?; file.write_all(&new_data).map_err(|_| Error::InsertData); Ok(new_task.into()) } } impl FsRepo { fn get_tasks_impl(&self) -> Result, Error> { let file_path = self.xdg_dirs.get_data_file(DATA_FILE); File::open(&file_path) .map_err(|_| Error::NotFound) .and_then(|file| serde_json::from_reader(file).map_err(|_| Error::InvalidData)) } }