1use super::unixfile::UnixFileLoader;
2use crate::{
3 db::DB,
4 filenames::saturn_db,
5 record::{Record, RecurringRecord},
6 time::now,
7};
8use anyhow::{anyhow, Result};
9use async_trait::async_trait;
10use chrono::Timelike;
11use serde::{Deserialize, Serialize};
12use std::collections::BTreeMap;
13
14#[derive(Debug, Clone, Serialize, Deserialize, Default)]
15pub struct MemoryDB {
16 primary_key: u64,
17 records: BTreeMap<u64, Record>,
18 recurrence_key: u64,
19 recurring: BTreeMap<u64, RecurringRecord>,
20}
21
22impl MemoryDB {
23 pub fn new() -> Self {
24 Self::default()
25 }
26}
27
28#[async_trait]
29impl DB for MemoryDB {
30 async fn load(&mut self) -> Result<()> {
31 let db: Self = UnixFileLoader::new(&saturn_db()).load().await?;
32 self.primary_key = db.primary_key;
33 self.records = db.records;
34 self.recurrence_key = db.recurrence_key;
35 self.recurring = db.recurring;
36 Ok(())
37 }
38
39 async fn dump(&self) -> Result<()> {
40 UnixFileLoader::new(&saturn_db()).dump(self.clone()).await
41 }
42
43 fn primary_key(&self) -> u64 {
44 self.primary_key
45 }
46
47 fn recurrence_key(&self) -> u64 {
48 self.recurrence_key
49 }
50
51 fn set_primary_key(&mut self, primary_key: u64) {
52 self.primary_key = primary_key;
53 }
54
55 fn set_recurrence_key(&mut self, primary_key: u64) {
56 self.recurrence_key = primary_key;
57 }
58
59 async fn delete(&mut self, primary_key: u64) -> Result<()> {
60 self.records.remove(&primary_key);
61 Ok(())
62 }
63
64 async fn delete_recurrence(&mut self, recurrence_key: u64) -> Result<Vec<String>> {
65 self.recurring.remove(&recurrence_key);
66 Ok(Vec::new()) }
68
69 async fn record(&mut self, record: Record) -> Result<()> {
70 self.records.insert(record.primary_key(), record);
71 Ok(())
72 }
73
74 async fn record_recurrence(&mut self, record: RecurringRecord) -> Result<()> {
75 self.recurring.insert(record.recurrence_key(), record);
76 Ok(())
77 }
78
79 async fn insert_record(&mut self, record: Record) -> Result<()> {
80 self.record(record).await
81 }
82
83 async fn insert_recurrence(&mut self, record: RecurringRecord) -> Result<()> {
84 self.record_recurrence(record).await
85 }
86
87 async fn list_recurrence(&mut self) -> Result<Vec<RecurringRecord>> {
88 let mut v = Vec::new();
89
90 for (_, val) in &self.recurring {
91 v.push(val.clone());
92 }
93
94 Ok(v)
95 }
96
97 async fn update_recurrence(&mut self) -> Result<()> {
98 let mut recurring = self.recurring.clone();
99 let records = self.records.clone();
100
101 for (_, recur) in &mut recurring {
102 let mut seen: Option<&Record> = None;
103
104 let mut begin = recur.record().datetime();
105 let tomorrow = (now() + chrono::TimeDelta::try_days(1).unwrap_or_default()).date_naive();
106
107 while begin.date_naive() <= tomorrow {
108 for (_, record) in &records {
109 if let Some(key) = record.recurrence_key() {
110 if key == recur.recurrence_key() && record.datetime() == begin {
111 seen = Some(record);
112 }
113 }
114 }
115
116 if seen.is_none() {
117 let key = self.next_key();
118 self.record(recur.record_from(key, begin.naive_local()))
119 .await?;
120 }
121
122 begin += recur.recurrence().duration();
123 }
124 }
125
126 Ok(())
127 }
128
129 async fn list_today(&mut self, include_completed: bool) -> Result<Vec<Record>> {
130 let today = now().date_naive();
131
132 Ok(self
133 .records
134 .iter()
135 .filter_map(|(_, v)| {
136 if v.date() != today || (v.completed() && !include_completed) {
137 None
138 } else {
139 Some(v.clone())
140 }
141 })
142 .collect::<Vec<Record>>())
143 }
144
145 async fn list_all(&mut self, include_completed: bool) -> Result<Vec<Record>> {
146 let values = self
147 .records
148 .iter()
149 .filter(|(_, v)| {
150 if v.completed() && !include_completed {
151 false
152 } else {
153 true
154 }
155 })
156 .collect::<BTreeMap<&u64, &Record>>();
157
158 let mut v = Vec::new();
159
160 for (_, val) in values {
161 v.push(val.clone())
162 }
163
164 Ok(v)
165 }
166
167 async fn events_now(
168 &mut self,
169 last: chrono::Duration,
170 include_completed: bool,
171 ) -> Result<Vec<Record>> {
172 let mut ret = Vec::new();
173 let n = now().date_naive();
174
175 let mut records = Vec::new();
176
177 for record in self.records.iter().filter(|(_, v)| v.date() == n) {
178 records.push(record);
179 }
180
181 let n = n + chrono::TimeDelta::try_days(1).unwrap_or_default();
182
183 let mut next_day = self.records.iter().filter(|(_, v)| v.date() == n).collect();
184
185 records.append(&mut next_day);
186
187 for (_, item) in records {
188 if item.completed() && !include_completed {
189 continue;
190 }
191
192 if let Some(at) = item.at() {
193 if at - now().time() < last && now().time() < at {
194 ret.push(item.clone());
195 }
196 } else if let Some(schedule) = item.scheduled() {
197 if (schedule.0 - last) < now().time() && (schedule.1 + last) > now().time() {
198 ret.push(item.clone())
199 }
200 } else if item.all_day()
201 && item.date() - chrono::TimeDelta::try_days(1).unwrap_or_default() == now().date_naive()
202 && now().time() > chrono::NaiveTime::from_hms_opt(23, 59, 0).unwrap() - last
203 {
204 ret.push(item.clone())
205 } else {
206 let dt = item.datetime();
207 let n = now();
208 if dt > n && n > dt - last {
209 ret.push(item.clone());
210 } else if let Some(notifications) = item.notifications() {
211 for notification in notifications {
212 let dt_window = dt - notification.duration();
213 let dt_time = dt_window
214 .time()
215 .with_second(0)
216 .unwrap()
217 .with_nanosecond(0)
218 .unwrap();
219 let n_time = n.time().with_second(0).unwrap().with_nanosecond(0).unwrap();
220
221 if dt > n && dt_window.date_naive() == n.date_naive() && dt_time == n_time {
222 ret.push(item.clone());
223 break;
224 }
225 }
226 }
227 }
228 }
229
230 Ok(ret)
231 }
232
233 async fn complete_task(&mut self, primary_key: u64) -> Result<()> {
234 for record in self.records.values_mut() {
235 if record.primary_key() == primary_key {
236 record.set_completed(true);
237 }
238 }
239
240 Ok(())
241 }
242
243 async fn get(&mut self, primary_key: u64) -> Result<Record> {
244 let mut record: Option<Record> = None;
245 for r in self.records.values() {
246 if primary_key == r.primary_key() {
247 record = Some(r.clone());
248 break;
249 }
250 }
251
252 record.ok_or(anyhow!("No Record Found"))
253 }
254
255 async fn get_recurring(&mut self, recurrence_key: u64) -> Result<RecurringRecord> {
256 self.recurring
257 .get(&recurrence_key)
258 .ok_or(anyhow!("No Record Found"))
259 .cloned()
260 }
261
262 async fn update(&mut self, record: Record) -> Result<()> {
263 self.records.insert(record.primary_key(), record);
264 Ok(())
265 }
266
267 async fn update_recurring(&mut self, record: RecurringRecord) -> Result<()> {
268 self.recurring.insert(record.recurrence_key(), record);
269 Ok(())
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 #[tokio::test]
276 async fn test_recording() {
277 use crate::db::{memory::MemoryDB, unixfile::UnixFileLoader, DB};
278 use crate::record::Record;
279
280 let mut db = MemoryDB::new();
281
282 for x in 0..(rand::random::<u64>() % 50) + 1 {
283 assert!(db
284 .record(
285 Record::build()
286 .set_primary_key(x)
287 .set_date(
288 chrono::NaiveDate::from_ymd_opt(
289 rand::random::<i32>() % 5 + 2023,
290 rand::random::<u32>() % 12 + 1,
291 rand::random::<u32>() % 28 + 1,
292 )
293 .unwrap(),
294 )
295 .set_at(Some(
296 chrono::NaiveTime::from_hms_opt(
297 rand::random::<u32>() % 24,
298 rand::random::<u32>() % 60,
299 0,
300 )
301 .unwrap(),
302 ))
303 .clone(),
304 )
305 .await
306 .is_ok());
307 }
308
309 let f = tempfile::NamedTempFile::new().unwrap();
310 assert!(UnixFileLoader::new(&f.path().to_path_buf())
311 .dump(db.clone())
312 .await
313 .is_ok());
314
315 let db2: MemoryDB = UnixFileLoader::new(&f.path().to_path_buf())
316 .load()
317 .await
318 .unwrap();
319 assert_eq!(db.primary_key, db2.primary_key);
320 assert_eq!(db.records, db2.records);
321 }
322}