diff --git a/lib/domain/libimagdiary/src/diary.rs b/lib/domain/libimagdiary/src/diary.rs index 431b6320..be768fed 100644 --- a/lib/domain/libimagdiary/src/diary.rs +++ b/lib/domain/libimagdiary/src/diary.rs @@ -19,6 +19,7 @@ use std::cmp::Ordering; +use libimagstore::store::FileLockEntry; use libimagstore::store::Store; use libimagstore::storeid::IntoStoreId; use libimagerror::trace::trace_error; @@ -27,102 +28,136 @@ use chrono::offset::Local; use chrono::Datelike; use itertools::Itertools; use chrono::naive::NaiveDateTime; +use chrono::Timelike; use entry::Entry; use diaryid::DiaryId; -use error::DiaryError as DE; use error::DiaryErrorKind as DEK; +use error::MapErrInto; use result::Result; use iter::DiaryEntryIterator; -use is_in_diary::IsInDiary; +use iter::DiaryNameIterator; -#[derive(Debug)] -pub struct Diary<'a> { - store: &'a Store, - name: &'a str, -} +trait Diary { -impl<'a> Diary<'a> { + /// Wrapper around Store::get for DiaryId + fn get(&self, id: DiaryId) -> Result>; - pub fn open(store: &'a Store, name: &'a str) -> Diary<'a> { - Diary { - store: store, - name: name, - } - } + /// Wrapper around Store::retrieve for DiaryId + fn retrieve(&self, id: DiaryId) -> Result; + + /// Wrapper around Store::delete for DiaryId + fn delete(&self, entry: Entry) -> Result<()>; // create or get a new entry for today - pub fn new_entry_today(&self) -> Result { - let dt = Local::now(); - let ndt = dt.naive_local(); - let id = DiaryId::new(String::from(self.name), ndt.year(), ndt.month(), ndt.day(), 0, 0); - self.new_entry_by_id(id) + fn new_entry_today(&self, diary_name: &str) -> Result; + + // create or get a new entry for now + fn new_entry_now(&self, diary_name: &str) -> Result; + + // Get an iterator for iterating over all entries of a Diary + fn entries(&self, diary_name: &str) -> Result; + + fn get_youngest_entry_id(&self, diary_name: &str) -> Option>; + + /// Get all diary names + fn diary_names(&self) -> Result; + +} + +impl Diary for Store { + + + /// Wrapper around Store::get for DiaryId + fn get(&self, id: DiaryId) -> Result> { + id.into_storeid().and_then(|id| self.get(id)).map_err_into(DEK::StoreWriteError) } - pub fn new_entry_by_id(&self, id: DiaryId) -> Result { - self.retrieve(id.with_diary_name(String::from(self.name))) + /// Wrapper around Store::retrieve for DiaryId + fn retrieve(&self, id: DiaryId) -> Result { + id.into_storeid().and_then(|id| self.retrieve(id)).map_err_into(DEK::StoreWriteError) } - pub fn retrieve(&self, id: DiaryId) -> Result { - id.into_storeid() - .and_then(|id| self.store.retrieve(id)) - .map(|fle| Entry::new(fle)) - .map_err(|e| DE::new(DEK::StoreWriteError, Some(Box::new(e)))) - } - - // Get an iterator for iterating over all entries - pub fn entries(&self) -> Result> { - self.store - .retrieve_for_module("diary") - .map(|iter| DiaryEntryIterator::new(self.name, self.store, iter)) - .map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e)))) - } - - pub fn delete_entry(&self, entry: Entry) -> Result<()> { - if !entry.is_in_diary(self.name) { - return Err(DE::new(DEK::EntryNotInDiary, None)); - } + /// Wrapper around Store::delete for DiaryId + fn delete(&self, entry: Entry) -> Result<()> { let id = entry.get_location().clone(); drop(entry); - self.store.delete(id) - .map_err(|e| DE::new(DEK::StoreWriteError, Some(Box::new(e)))) + self.delete(id).map_err_into(DEK::StoreWriteError) } - pub fn get_youngest_entry(&self) -> Option> { - match self.entries() { + // create or get a new entry for today + fn new_entry_today(&self, diary_name: &str) -> Result { + let dt = Local::now(); + let ndt = dt.naive_local(); + let id = DiaryId::new(String::from(diary_name), ndt.year(), ndt.month(), ndt.day(), 0, 0); + Diary::retrieve(self, id) + } + + // create or get a new entry for today + fn new_entry_now(&self, diary_name: &str) -> Result { + let dt = Local::now(); + let ndt = dt.naive_local(); + let id = DiaryId::new(String::from(diary_name), + ndt.year(), + ndt.month(), + ndt.day(), + ndt.minute(), + ndt.second()); + + Diary::retrieve(self, id) + } + + // Get an iterator for iterating over all entries + fn entries(&self, diary_name: &str) -> Result { + self.retrieve_for_module("diary") + .map(|iter| DiaryEntryIterator::new(self, String::from(diary_name), iter)) + .map_err_into(DEK::StoreReadError) + } + + fn get_youngest_entry_id(&self, diary_name: &str) -> Option> { + match Diary::entries(self, diary_name) { Err(e) => Some(Err(e)), Ok(entries) => { - entries.sorted_by(|a, b| { - match (a, b) { - (&Ok(ref a), &Ok(ref b)) => { - let a : NaiveDateTime = a.diary_id().into(); - let b : NaiveDateTime = b.diary_id().into(); + entries + .map(|e| e.and_then(|e| e.diary_id())) + .sorted_by(|a, b| { + match (a, b) { + (&Ok(ref a), &Ok(ref b)) => { + let a : NaiveDateTime = a.clone().into(); + let b : NaiveDateTime = b.clone().into(); - a.cmp(&b) - }, + a.cmp(&b) + }, - (&Ok(_), &Err(ref e)) => { - trace_error(e); - Ordering::Less - }, - (&Err(ref e), &Ok(_)) => { - trace_error(e); - Ordering::Greater - }, - (&Err(ref e1), &Err(ref e2)) => { - trace_error(e1); - trace_error(e2); - Ordering::Equal - }, - } - }).into_iter().next() + (&Ok(_), &Err(ref e)) => { + trace_error(e); + Ordering::Less + }, + (&Err(ref e), &Ok(_)) => { + trace_error(e); + Ordering::Greater + }, + (&Err(ref e1), &Err(ref e2)) => { + trace_error(e1); + trace_error(e2); + Ordering::Equal + }, + } + }) + .into_iter() + //.map(|sidres| sidres.map(|sid| DiaryId::from_storeid(&sid))) + .next() } } } - pub fn name(&self) -> &'a str { - &self.name + /// Get all diary names + fn diary_names(&self) -> Result { + self.retrieve_for_module("diary") + .map_err_into(DEK::StoreReadError) + .map(DiaryNameIterator::new) } + } diff --git a/lib/domain/libimagdiary/src/entry.rs b/lib/domain/libimagdiary/src/entry.rs index 0148b59d..d0fb2e53 100644 --- a/lib/domain/libimagdiary/src/entry.rs +++ b/lib/domain/libimagdiary/src/entry.rs @@ -27,6 +27,7 @@ use libimagrt::runtime::Runtime; use diaryid::DiaryId; use diaryid::FromStoreId; +use result::Result; #[derive(Debug)] pub struct Entry<'a>(FileLockEntry<'a>); @@ -57,8 +58,8 @@ impl<'a> Entry<'a> { /// Get the diary id for this entry. /// /// TODO: calls Option::unwrap() as it assumes that an existing Entry has an ID that is parsable - pub fn diary_id(&self) -> DiaryId { - DiaryId::from_storeid(&self.0.get_location().clone()).unwrap() + pub fn diary_id(&self) -> Result { + DiaryId::from_storeid(&self.0.get_location().clone()) } } diff --git a/lib/domain/libimagdiary/src/error.rs b/lib/domain/libimagdiary/src/error.rs index b5406b12..1164f806 100644 --- a/lib/domain/libimagdiary/src/error.rs +++ b/lib/domain/libimagdiary/src/error.rs @@ -28,7 +28,8 @@ generate_error_module!( EntryNotInDiary => "Entry not in Diary", IOError => "IO Error", ViewError => "Error viewing diary entry", - IdParseError => "Error while parsing ID" + IdParseError => "Error while parsing ID", + DiaryNameFindingError => "Error while finding a diary name" ); ); diff --git a/lib/domain/libimagdiary/src/iter.rs b/lib/domain/libimagdiary/src/iter.rs index de849872..2ed40ece 100644 --- a/lib/domain/libimagdiary/src/iter.rs +++ b/lib/domain/libimagdiary/src/iter.rs @@ -22,6 +22,8 @@ use std::result::Result as RResult; use libimagstore::store::Store; use libimagstore::storeid::StoreIdIterator; +use libimagerror::trace::trace_error; +use libimagerror::into::IntoError; use diaryid::DiaryId; use diaryid::FromStoreId; @@ -29,13 +31,14 @@ use is_in_diary::IsInDiary; use entry::Entry as DiaryEntry; use error::DiaryError as DE; use error::DiaryErrorKind as DEK; +use error::MapErrInto; use result::Result; -use libimagerror::trace::trace_error; +use is_in_diary::IsInDiary; /// A iterator for iterating over diary entries pub struct DiaryEntryIterator<'a> { store: &'a Store, - name: &'a str, + name: String, iter: StoreIdIterator, year: Option, @@ -54,7 +57,7 @@ impl<'a> Debug for DiaryEntryIterator<'a> { impl<'a> DiaryEntryIterator<'a> { - pub fn new(diaryname: &'a str, store: &'a Store, iter: StoreIdIterator) -> DiaryEntryIterator<'a> { + pub fn new(store: &'a Store, diaryname: String, iter: StoreIdIterator) -> DiaryEntryIterator<'a> { DiaryEntryIterator { store: store, name: diaryname, @@ -97,7 +100,7 @@ impl<'a> Iterator for DiaryEntryIterator<'a> { }; debug!("Next element: {:?}", next); - if next.is_in_diary(self.name) { + if next.is_in_diary(&self.name) { debug!("Seems to be in diary: {:?}", next); let id = match DiaryId::from_storeid(&next) { Ok(i) => i, @@ -130,3 +133,37 @@ impl<'a> Iterator for DiaryEntryIterator<'a> { } + +/// Get diary names. +/// +/// # Warning +/// +/// Does _not_ run a `unique` on the iterator! +pub struct DiaryNameIterator(StoreIdIterator); + +impl DiaryNameIterator { + pub fn new(s: StoreIdIterator) -> DiaryNameIterator { + DiaryNameIterator(s) + } +} + +impl Iterator for DiaryNameIterator { + type Item = Result; + + fn next(&mut self) -> Option { + self.0 + .next() + .map(|s| { + s.to_str() + .map_err_into(DEK::DiaryNameFindingError) + .and_then(|s| { + s.split("diary/") + .nth(1) + .and_then(|n| n.split("/").nth(0).map(String::from)) + .ok_or(DEK::DiaryNameFindingError.into_error()) + }) + }) + } + +} + diff --git a/lib/domain/libimagdiary/src/viewer.rs b/lib/domain/libimagdiary/src/viewer.rs index 93b155a7..38c6e179 100644 --- a/lib/domain/libimagdiary/src/viewer.rs +++ b/lib/domain/libimagdiary/src/viewer.rs @@ -26,6 +26,7 @@ use result::Result; use libimagentryview::viewer::Viewer; use libimagentryview::builtin::plain::PlainViewer; +use libimagerror::trace::trace_error; /// This viewer does _not_ implement libimagentryview::viewer::Viewer because we need to be able to /// call some diary-type specific functions on the entries passed to this. @@ -48,8 +49,10 @@ impl DiaryViewer { /// error. pub fn view_entries<'a, I: Iterator>>(&self, entries: I) -> Result<()> { for entry in entries { - let id = entry.diary_id(); - println!("{} :\n", id); + match entry.diary_id() { + Ok(id) => println!("{} :\n", id), + Err(e) => trace_error(&e), + } let _ = try!(self.0 .view_entry(&entry) .map_err_into(DEK::ViewError)