reminder_cli/
storage.rs

1use crate::reminder::Reminder;
2use anyhow::{Context, Result};
3use std::fs;
4use std::path::PathBuf;
5use uuid::Uuid;
6
7pub struct Storage {
8    path: PathBuf,
9}
10
11impl Storage {
12    pub fn new() -> Result<Self> {
13        let data_dir = dirs::data_local_dir()
14            .context("Failed to get local data directory")?
15            .join("reminder-cli");
16        
17        fs::create_dir_all(&data_dir)?;
18        
19        Ok(Self {
20            path: data_dir.join("reminders.json"),
21        })
22    }
23
24    pub fn load(&self) -> Result<Vec<Reminder>> {
25        if !self.path.exists() {
26            return Ok(Vec::new());
27        }
28
29        let content = fs::read_to_string(&self.path)
30            .context("Failed to read reminders file")?;
31        
32        if content.trim().is_empty() {
33            return Ok(Vec::new());
34        }
35
36        let reminders: Vec<Reminder> = serde_json::from_str(&content)
37            .context("Failed to parse reminders JSON")?;
38        
39        Ok(reminders)
40    }
41
42    pub fn save(&self, reminders: &[Reminder]) -> Result<()> {
43        let content = serde_json::to_string_pretty(reminders)
44            .context("Failed to serialize reminders")?;
45        
46        fs::write(&self.path, content)
47            .context("Failed to write reminders file")?;
48        
49        Ok(())
50    }
51
52    pub fn add(&self, reminder: Reminder) -> Result<()> {
53        let mut reminders = self.load()?;
54        reminders.push(reminder);
55        self.save(&reminders)
56    }
57
58    pub fn delete(&self, id: Uuid) -> Result<bool> {
59        let mut reminders = self.load()?;
60        let initial_len = reminders.len();
61        reminders.retain(|r| r.id != id);
62        
63        if reminders.len() == initial_len {
64            return Ok(false);
65        }
66        
67        self.save(&reminders)?;
68        Ok(true)
69    }
70
71    pub fn update(&self, id: Uuid, updater: impl FnOnce(&mut Reminder)) -> Result<bool> {
72        let mut reminders = self.load()?;
73        
74        if let Some(reminder) = reminders.iter_mut().find(|r| r.id == id) {
75            updater(reminder);
76            self.save(&reminders)?;
77            Ok(true)
78        } else {
79            Ok(false)
80        }
81    }
82
83    pub fn get(&self, id: Uuid) -> Result<Option<Reminder>> {
84        let reminders = self.load()?;
85        Ok(reminders.into_iter().find(|r| r.id == id))
86    }
87
88    pub fn pid_file_path() -> Result<PathBuf> {
89        let data_dir = dirs::data_local_dir()
90            .context("Failed to get local data directory")?
91            .join("reminder-cli");
92        
93        fs::create_dir_all(&data_dir)?;
94        Ok(data_dir.join("daemon.pid"))
95    }
96
97    pub fn log_file_path() -> Result<PathBuf> {
98        let data_dir = dirs::data_local_dir()
99            .context("Failed to get local data directory")?
100            .join("reminder-cli");
101        
102        fs::create_dir_all(&data_dir)?;
103        Ok(data_dir.join("daemon.log"))
104    }
105}