From 9c69645b69052fd1170484e390cbea363f784f9a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 28 Aug 2017 21:58:43 +0200 Subject: [PATCH 1/7] Implement Diary as trait --- lib/domain/libimagdiary/src/diary.rs | 171 ++++++++++++++++---------- lib/domain/libimagdiary/src/entry.rs | 5 +- lib/domain/libimagdiary/src/error.rs | 3 +- lib/domain/libimagdiary/src/iter.rs | 45 ++++++- lib/domain/libimagdiary/src/viewer.rs | 7 +- 5 files changed, 154 insertions(+), 77 deletions(-) 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) From 95b7da1ed21e4af5142b84bb49768a9c40b8dd68 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Aug 2017 10:52:10 +0200 Subject: [PATCH 2/7] Impl Entry (now DiaryEntry) as trait --- lib/domain/libimagdiary/src/diary.rs | 36 ++------------- lib/domain/libimagdiary/src/entry.rs | 63 +++------------------------ lib/domain/libimagdiary/src/iter.rs | 8 ++-- lib/domain/libimagdiary/src/viewer.rs | 5 ++- 4 files changed, 16 insertions(+), 96 deletions(-) diff --git a/lib/domain/libimagdiary/src/diary.rs b/lib/domain/libimagdiary/src/diary.rs index be768fed..cf738e33 100644 --- a/lib/domain/libimagdiary/src/diary.rs +++ b/lib/domain/libimagdiary/src/diary.rs @@ -21,7 +21,6 @@ use std::cmp::Ordering; use libimagstore::store::FileLockEntry; use libimagstore::store::Store; -use libimagstore::storeid::IntoStoreId; use libimagerror::trace::trace_error; use chrono::offset::Local; @@ -30,7 +29,7 @@ use itertools::Itertools; use chrono::naive::NaiveDateTime; use chrono::Timelike; -use entry::Entry; +use entry::DiaryEntry; use diaryid::DiaryId; use error::DiaryErrorKind as DEK; use error::MapErrInto; @@ -40,15 +39,6 @@ use iter::DiaryNameIterator; trait Diary { - /// Wrapper around Store::get for DiaryId - fn get(&self, id: DiaryId) -> Result>; - - /// 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 fn new_entry_today(&self, diary_name: &str) -> Result; @@ -67,31 +57,13 @@ trait Diary { 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) - } - - /// 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) - } - - /// Wrapper around Store::delete for DiaryId - fn delete(&self, entry: Entry) -> Result<()> { - let id = entry.get_location().clone(); - drop(entry); - - self.delete(id).map_err_into(DEK::StoreWriteError) - } - // 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) + + self.retrieve(id).map_err_into(DEK::StoreReadError) } // create or get a new entry for today @@ -105,7 +77,7 @@ impl Diary for Store { ndt.minute(), ndt.second()); - Diary::retrieve(self, id) + self.retrieve(id).map_err_into(DEK::StoreReadError) } // Get an iterator for iterating over all entries diff --git a/lib/domain/libimagdiary/src/entry.rs b/lib/domain/libimagdiary/src/entry.rs index d0fb2e53..2da96199 100644 --- a/lib/domain/libimagdiary/src/entry.rs +++ b/lib/domain/libimagdiary/src/entry.rs @@ -17,75 +17,24 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // -use std::ops::Deref; -use std::ops::DerefMut; - -use libimagstore::store::FileLockEntry; -use libimagentryedit::edit::Edit; -use libimagentryedit::result::Result as EditResult; -use libimagrt::runtime::Runtime; +use libimagstore::store::Entry; use diaryid::DiaryId; use diaryid::FromStoreId; use result::Result; -#[derive(Debug)] -pub struct Entry<'a>(FileLockEntry<'a>); - -impl<'a> Deref for Entry<'a> { - type Target = FileLockEntry<'a>; - - fn deref(&self) -> &FileLockEntry<'a> { - &self.0 - } - +pub trait DiaryEntry { + fn diary_id(&self) -> Result; } -impl<'a> DerefMut for Entry<'a> { - - fn deref_mut(&mut self) -> &mut FileLockEntry<'a> { - &mut self.0 - } - -} - -impl<'a> Entry<'a> { - - pub fn new(fle: FileLockEntry<'a>) -> Entry<'a> { - Entry(fle) - } +impl DiaryEntry for Entry { /// 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) -> Result { - DiaryId::from_storeid(&self.0.get_location().clone()) + fn diary_id(&self) -> Result { + DiaryId::from_storeid(&self.get_location().clone()) } } -impl<'a> Into> for Entry<'a> { - - fn into(self) -> FileLockEntry<'a> { - self.0 - } - -} - -impl<'a> From> for Entry<'a> { - - fn from(fle: FileLockEntry<'a>) -> Entry<'a> { - Entry::new(fle) - } - -} - -impl<'a> Edit for Entry<'a> { - - fn edit_content(&mut self, rt: &Runtime) -> EditResult<()> { - self.0.edit_content(rt) - } - -} - - diff --git a/lib/domain/libimagdiary/src/iter.rs b/lib/domain/libimagdiary/src/iter.rs index 2ed40ece..32fe407c 100644 --- a/lib/domain/libimagdiary/src/iter.rs +++ b/lib/domain/libimagdiary/src/iter.rs @@ -21,14 +21,13 @@ use std::fmt::{Debug, Formatter, Error as FmtError}; use std::result::Result as RResult; use libimagstore::store::Store; +use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreIdIterator; use libimagerror::trace::trace_error; use libimagerror::into::IntoError; use diaryid::DiaryId; use diaryid::FromStoreId; -use is_in_diary::IsInDiary; -use entry::Entry as DiaryEntry; use error::DiaryError as DE; use error::DiaryErrorKind as DEK; use error::MapErrInto; @@ -90,9 +89,9 @@ impl<'a> DiaryEntryIterator<'a> { } impl<'a> Iterator for DiaryEntryIterator<'a> { - type Item = Result>; + type Item = Result>; - fn next(&mut self) -> Option>> { + fn next(&mut self) -> Option { loop { let next = match self.iter.next() { Some(s) => s, @@ -121,7 +120,6 @@ impl<'a> Iterator for DiaryEntryIterator<'a> { return Some(self .store .retrieve(next) - .map(|fle| DiaryEntry::new(fle)) .map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e)))) ); } diff --git a/lib/domain/libimagdiary/src/viewer.rs b/lib/domain/libimagdiary/src/viewer.rs index 38c6e179..c0c03fc6 100644 --- a/lib/domain/libimagdiary/src/viewer.rs +++ b/lib/domain/libimagdiary/src/viewer.rs @@ -19,11 +19,12 @@ //! A diary viewer built on libimagentryview. -use entry::Entry; +use entry::DiaryEntry; use error::DiaryErrorKind as DEK; use error::MapErrInto; use result::Result; +use libimagstore::store::FileLockEntry; use libimagentryview::viewer::Viewer; use libimagentryview::builtin::plain::PlainViewer; use libimagerror::trace::trace_error; @@ -47,7 +48,7 @@ impl DiaryViewer { /// View all entries from the iterator, or stop immediately if an error occurs, returning that /// error. - pub fn view_entries<'a, I: Iterator>>(&self, entries: I) -> Result<()> { + pub fn view_entries<'a, I: Iterator>>(&self, entries: I) -> Result<()> { for entry in entries { match entry.diary_id() { Ok(id) => println!("{} :\n", id), From 31fa07d43acf2684c9ea43a4e65a4a8e44af4ee0 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Aug 2017 10:52:22 +0200 Subject: [PATCH 3/7] Add another small helper --- lib/domain/libimagdiary/src/is_in_diary.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/domain/libimagdiary/src/is_in_diary.rs b/lib/domain/libimagdiary/src/is_in_diary.rs index 09228072..8b48e1cc 100644 --- a/lib/domain/libimagdiary/src/is_in_diary.rs +++ b/lib/domain/libimagdiary/src/is_in_diary.rs @@ -24,6 +24,8 @@ pub trait IsInDiary { fn is_in_diary(&self, name: &str) -> bool; + fn is_a_diary_entry(&self) -> bool; + } impl IsInDiary for Entry { @@ -32,6 +34,10 @@ impl IsInDiary for Entry { self.get_location().clone().is_in_diary(name) } + fn is_a_diary_entry(&self) -> bool { + self.get_location().clone().is_a_diary_entry() + } + } impl IsInDiary for StoreId { @@ -40,5 +46,9 @@ impl IsInDiary for StoreId { self.local().starts_with(format!("diary/{}", name)) } + fn is_a_diary_entry(&self) -> bool { + self.local().starts_with("diary") + } + } From 21c15ca2070b35ea91b52208e8a1217404fd8458 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Aug 2017 16:04:11 +0200 Subject: [PATCH 4/7] Adapt imag-diary to compile with the new libimagdiary API --- bin/domain/imag-diary/src/create.rs | 45 ++++++++++++++++------------ bin/domain/imag-diary/src/delete.rs | 27 ++++++++++++----- bin/domain/imag-diary/src/edit.rs | 35 ++++++++++++++++------ bin/domain/imag-diary/src/list.rs | 4 +-- bin/domain/imag-diary/src/view.rs | 3 +- lib/domain/libimagdiary/src/diary.rs | 2 +- 6 files changed, 74 insertions(+), 42 deletions(-) diff --git a/bin/domain/imag-diary/src/create.rs b/bin/domain/imag-diary/src/create.rs index 78f679a7..61b892b6 100644 --- a/bin/domain/imag-diary/src/create.rs +++ b/bin/domain/imag-diary/src/create.rs @@ -26,9 +26,10 @@ use libimagdiary::error::MapErrInto; use libimagentryedit::edit::Edit; use libimagrt::runtime::Runtime; use libimagerror::trace::trace_error; -use libimagdiary::entry::Entry; -use libimagdiary::result::Result; +use libimagerror::trace::trace_error_exit; use libimagutil::warn_exit::warn_exit; +use libimagstore::store::FileLockEntry; +use libimagstore::store::Store; use util::get_diary_name; @@ -38,18 +39,18 @@ pub fn create(rt: &Runtime) { let prevent_edit = rt.cli().subcommand_matches("create").unwrap().is_present("no-edit"); - fn create_entry<'a>(diary: &'a Diary, rt: &Runtime) -> Result> { + fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> FileLockEntry<'a> { use std::str::FromStr; let create = rt.cli().subcommand_matches("create").unwrap(); - if !create.is_present("timed") { + let entry = if !create.is_present("timed") { debug!("Creating non-timed entry"); - diary.new_entry_today() + diary.new_entry_today(diaryname) } else { let id = match create.value_of("timed") { Some("h") | Some("hourly") => { debug!("Creating hourly-timed entry"); - let time = DiaryId::now(String::from(diary.name())); + let time = DiaryId::now(String::from(diaryname)); let hr = create .value_of("hour") .map(|v| { debug!("Creating hourly entry with hour = {:?}", v); v }) @@ -65,7 +66,7 @@ pub fn create(rt: &Runtime) { Some("m") | Some("minutely") => { debug!("Creating minutely-timed entry"); - let time = DiaryId::now(String::from(diary.name())); + let time = DiaryId::now(String::from(diaryname)); let hr = create .value_of("hour") .map(|h| { debug!("hour = {:?}", h); h }) @@ -98,21 +99,27 @@ pub fn create(rt: &Runtime) { None => warn_exit("Unexpected error, cannot continue", 1) }; - diary.new_entry_by_id(id) + diary.retrieve(id).map_err_into(DEK::StoreReadError) + }; + + match entry { + Err(e) => trace_error_exit(&e, 1), + Ok(e) => { + debug!("Created: {}", e.get_location()); + e + } } } - let diary = Diary::open(rt.store(), &diaryname[..]); - let res = create_entry(&diary, rt) - .and_then(|mut entry| { - if prevent_edit { - debug!("Not editing new diary entry"); - Ok(()) - } else { - debug!("Editing new diary entry"); - entry.edit_content(rt).map_err_into(DEK::DiaryEditError) - } - }); + let mut entry = create_entry(rt.store(), &diaryname, rt); + + let res = if prevent_edit { + debug!("Not editing new diary entry"); + Ok(()) + } else { + debug!("Editing new diary entry"); + entry.edit_content(rt).map_err_into(DEK::DiaryEditError) + }; if let Err(e) = res { trace_error(&e); diff --git a/bin/domain/imag-diary/src/delete.rs b/bin/domain/imag-diary/src/delete.rs index da44bc92..514700f7 100644 --- a/bin/domain/imag-diary/src/delete.rs +++ b/bin/domain/imag-diary/src/delete.rs @@ -17,15 +17,17 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // +use std::process::exit; + use chrono::naive::NaiveDateTime; -use libimagdiary::diary::Diary; use libimagdiary::diaryid::DiaryId; use libimagrt::runtime::Runtime; use libimagerror::trace::trace_error_exit; use libimagtimeui::datetime::DateTime; use libimagtimeui::parse::Parse; use libimagutil::warn_exit::warn_exit; +use libimagstore::storeid::IntoStoreId; use util::get_diary_name; @@ -35,9 +37,6 @@ pub fn delete(rt: &Runtime) { let diaryname = get_diary_name(rt) .unwrap_or_else(|| warn_exit("No diary selected. Use either the configuration file or the commandline option", 1)); - let diary = Diary::open(rt.store(), &diaryname[..]); - debug!("Diary opened: {:?}", diary); - let datetime : Option = rt .cli() .subcommand_matches("delete") @@ -48,8 +47,17 @@ pub fn delete(rt: &Runtime) { .map(|dt| dt.into()); let to_del = match datetime { - Some(dt) => Some(diary.retrieve(DiaryId::from_datetime(diaryname.clone(), dt))), - None => diary.get_youngest_entry(), + Some(dt) => { + let id = match DiaryId::from_datetime(diaryname.clone(), dt).into_storeid() { + Ok(id) => id, + Err(e) => trace_error_exit(&e, 1), + }; + Some(rt.store().retrieve(id)) + }, + None => { + warn!("Not deleting entries, because missing date/time specification"); + exit(1); + }, }; let to_del = match to_del { @@ -59,12 +67,15 @@ pub fn delete(rt: &Runtime) { None => warn_exit("No entry", 1) }; - if !ask_bool(&format!("Deleting {:?}", to_del.get_location())[..], Some(true)) { + let location = to_del.get_location().clone(); + drop(to_del); + + if !ask_bool(&format!("Deleting {:?}", location), Some(true)) { info!("Aborting delete action"); return; } - if let Err(e) = diary.delete_entry(to_del) { + if let Err(e) = rt.store().delete(location) { trace_error_exit(&e, 1) } diff --git a/bin/domain/imag-diary/src/edit.rs b/bin/domain/imag-diary/src/edit.rs index 1cd5f9e5..3f9e59cf 100644 --- a/bin/domain/imag-diary/src/edit.rs +++ b/bin/domain/imag-diary/src/edit.rs @@ -17,6 +17,8 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // +use std::process::exit; + use chrono::naive::NaiveDateTime; use libimagdiary::diary::Diary; @@ -30,12 +32,13 @@ use libimagerror::into::IntoError; use libimagtimeui::datetime::DateTime; use libimagtimeui::parse::Parse; use libimagutil::warn_exit::warn_exit; +use libimagstore::storeid::IntoStoreId; +use libimagerror::trace::trace_error_exit; use util::get_diary_name; pub fn edit(rt: &Runtime) { let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1)); - let diary = Diary::open(rt.store(), &diaryname[..]); let datetime : Option = rt .cli() @@ -46,16 +49,30 @@ pub fn edit(rt: &Runtime) { .map(|dt| dt.into()); let to_edit = match datetime { - Some(dt) => Some(diary.retrieve(DiaryId::from_datetime(diaryname.clone(), dt))), - None => diary.get_youngest_entry(), + Some(dt) => { + let id = match DiaryId::from_datetime(diaryname.clone(), dt).into_storeid() { + Ok(id) => id, + Err(e) => trace_error_exit(&e, 1), + }; + rt.store().get(id) + }, + None => match rt.store().get_youngest_entry_id(&diaryname) { + Some(Ok(id)) => match id.into_storeid() { + Ok(sid) => rt.store().get(sid), + Err(e) => trace_error_exit(&e, 1), + }, + Some(Err(e)) => trace_error_exit(&e, 1), + None => { + error!("No entries in diary. Aborting"); + exit(1) + } + } }; - match to_edit { - Some(Ok(mut e)) => e.edit_content(rt).map_err_into(DEK::IOError), - - Some(Err(e)) => Err(e), - None => Err(DEK::EntryNotInDiary.into_error()), - } + to_edit.map(|opte| match opte { + Some(mut e) => e.edit_content(rt).map_err_into(DEK::IOError), + None => Err(DEK::EntryNotInDiary.into_error()), + }) .map_err_trace().ok(); } diff --git a/bin/domain/imag-diary/src/list.rs b/bin/domain/imag-diary/src/list.rs index 4ed3123c..90a8dd96 100644 --- a/bin/domain/imag-diary/src/list.rs +++ b/bin/domain/imag-diary/src/list.rs @@ -42,9 +42,7 @@ pub fn list(rt: &Runtime) { .unwrap_or(String::from("<>")) } - let diary = Diary::open(rt.store(), &diaryname[..]); - debug!("Diary opened: {:?}", diary); - diary.entries() + Diary::entries(rt.store(), &diaryname) .and_then(|es| { debug!("Iterator for listing: {:?}", es); diff --git a/bin/domain/imag-diary/src/view.rs b/bin/domain/imag-diary/src/view.rs index 041a1fe0..1e60383b 100644 --- a/bin/domain/imag-diary/src/view.rs +++ b/bin/domain/imag-diary/src/view.rs @@ -27,10 +27,9 @@ use util::get_diary_name; pub fn view(rt: &Runtime) { let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1)); - let diary = Diary::open(rt.store(), &diaryname[..]); let hdr = rt.cli().subcommand_matches("view").unwrap().is_present("show-header"); - diary.entries() + Diary::entries(rt.store(), &diaryname) .and_then(|entries| DV::new(hdr).view_entries(entries.into_iter().filter_map(Result::ok))) .map_err_trace() .ok(); diff --git a/lib/domain/libimagdiary/src/diary.rs b/lib/domain/libimagdiary/src/diary.rs index cf738e33..c67467cc 100644 --- a/lib/domain/libimagdiary/src/diary.rs +++ b/lib/domain/libimagdiary/src/diary.rs @@ -37,7 +37,7 @@ use result::Result; use iter::DiaryEntryIterator; use iter::DiaryNameIterator; -trait Diary { +pub trait Diary { // create or get a new entry for today fn new_entry_today(&self, diary_name: &str) -> Result; From 7e7cf8ecf83fef1dff15150bcca003e1eb9d89bf Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Aug 2017 16:10:09 +0200 Subject: [PATCH 5/7] Refactor, minify delete() impl --- bin/domain/imag-diary/src/delete.rs | 41 +++++++++++------------------ 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/bin/domain/imag-diary/src/delete.rs b/bin/domain/imag-diary/src/delete.rs index 514700f7..17f24a91 100644 --- a/bin/domain/imag-diary/src/delete.rs +++ b/bin/domain/imag-diary/src/delete.rs @@ -37,45 +37,34 @@ pub fn delete(rt: &Runtime) { let diaryname = get_diary_name(rt) .unwrap_or_else(|| warn_exit("No diary selected. Use either the configuration file or the commandline option", 1)); - let datetime : Option = rt + let to_del_location = rt .cli() .subcommand_matches("delete") .unwrap() .value_of("datetime") .map(|dt| { debug!("DateTime = {:?}", dt); dt }) .and_then(DateTime::parse) - .map(|dt| dt.into()); - - let to_del = match datetime { - Some(dt) => { - let id = match DiaryId::from_datetime(diaryname.clone(), dt).into_storeid() { - Ok(id) => id, - Err(e) => trace_error_exit(&e, 1), - }; - Some(rt.store().retrieve(id)) - }, - None => { + .map(|dt| dt.into()) + .ok_or_else(|| { warn!("Not deleting entries, because missing date/time specification"); exit(1); - }, - }; + }) + .and_then(|dt: NaiveDateTime| { + DiaryId::from_datetime(diaryname.clone(), dt) + .into_storeid() + .map(|id| rt.store().retrieve(id)) + .unwrap_or_else(|e| trace_error_exit(&e, 1)) + }) + .unwrap_or_else(|e| trace_error_exit(&e, 1)) + .get_location() + .clone(); - let to_del = match to_del { - Some(Ok(e)) => e, - - Some(Err(e)) => trace_error_exit(&e, 1), - None => warn_exit("No entry", 1) - }; - - let location = to_del.get_location().clone(); - drop(to_del); - - if !ask_bool(&format!("Deleting {:?}", location), Some(true)) { + if !ask_bool(&format!("Deleting {:?}", to_del_location), Some(true)) { info!("Aborting delete action"); return; } - if let Err(e) = rt.store().delete(location) { + if let Err(e) = rt.store().delete(to_del_location) { trace_error_exit(&e, 1) } From 356c86fd511d3e4f683620bc0feb3fbff4144e35 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Aug 2017 16:26:57 +0200 Subject: [PATCH 6/7] Refactor, minify create() impl --- bin/domain/imag-diary/src/create.rs | 153 ++++++++++++++-------------- 1 file changed, 75 insertions(+), 78 deletions(-) diff --git a/bin/domain/imag-diary/src/create.rs b/bin/domain/imag-diary/src/create.rs index 61b892b6..b93c2805 100644 --- a/bin/domain/imag-diary/src/create.rs +++ b/bin/domain/imag-diary/src/create.rs @@ -19,13 +19,14 @@ use std::process::exit; +use clap::ArgMatches; + use libimagdiary::diary::Diary; use libimagdiary::diaryid::DiaryId; use libimagdiary::error::DiaryErrorKind as DEK; use libimagdiary::error::MapErrInto; use libimagentryedit::edit::Edit; use libimagrt::runtime::Runtime; -use libimagerror::trace::trace_error; use libimagerror::trace::trace_error_exit; use libimagutil::warn_exit::warn_exit; use libimagstore::store::FileLockEntry; @@ -37,94 +38,90 @@ pub fn create(rt: &Runtime) { let diaryname = get_diary_name(rt) .unwrap_or_else( || warn_exit("No diary selected. Use either the configuration file or the commandline option", 1)); - let prevent_edit = rt.cli().subcommand_matches("create").unwrap().is_present("no-edit"); - - fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> FileLockEntry<'a> { - use std::str::FromStr; - - let create = rt.cli().subcommand_matches("create").unwrap(); - let entry = if !create.is_present("timed") { - debug!("Creating non-timed entry"); - diary.new_entry_today(diaryname) - } else { - let id = match create.value_of("timed") { - Some("h") | Some("hourly") => { - debug!("Creating hourly-timed entry"); - let time = DiaryId::now(String::from(diaryname)); - let hr = create - .value_of("hour") - .map(|v| { debug!("Creating hourly entry with hour = {:?}", v); v }) - .and_then(|s| { - FromStr::from_str(s) - .map_err(|_| warn!("Could not parse hour: '{}'", s)) - .ok() - }) - .unwrap_or(time.hour()); - - time.with_hour(hr).with_minute(0) - }, - - Some("m") | Some("minutely") => { - debug!("Creating minutely-timed entry"); - let time = DiaryId::now(String::from(diaryname)); - let hr = create - .value_of("hour") - .map(|h| { debug!("hour = {:?}", h); h }) - .and_then(|s| { - FromStr::from_str(s) - .map_err(|_| warn!("Could not parse hour: '{}'", s)) - .ok() - }) - .unwrap_or(time.hour()); - - let min = create - .value_of("minute") - .map(|m| { debug!("minute = {:?}", m); m }) - .and_then(|s| { - FromStr::from_str(s) - .map_err(|_| warn!("Could not parse minute: '{}'", s)) - .ok() - }) - .unwrap_or(time.minute()); - - time.with_hour(hr).with_minute(min) - }, - - Some(_) => { - warn!("Timed creation failed: Unknown spec '{}'", - create.value_of("timed").unwrap()); - exit(1); - }, - - None => warn_exit("Unexpected error, cannot continue", 1) - }; - - diary.retrieve(id).map_err_into(DEK::StoreReadError) - }; - - match entry { - Err(e) => trace_error_exit(&e, 1), - Ok(e) => { - debug!("Created: {}", e.get_location()); - e - } - } - } - let mut entry = create_entry(rt.store(), &diaryname, rt); - let res = if prevent_edit { + let res = if rt.cli().subcommand_matches("create").unwrap().is_present("no-edit") { debug!("Not editing new diary entry"); Ok(()) } else { debug!("Editing new diary entry"); - entry.edit_content(rt).map_err_into(DEK::DiaryEditError) + entry.edit_content(rt) + .map_err_into(DEK::DiaryEditError) }; if let Err(e) = res { - trace_error(&e); + trace_error_exit(&e, 1); } else { info!("Ok!"); } } +fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> FileLockEntry<'a> { + let create = rt.cli().subcommand_matches("create").unwrap(); + let entry = if !create.is_present("timed") { + debug!("Creating non-timed entry"); + diary.new_entry_today(diaryname) + } else { + let id = create_id_from_clispec(&create, &diaryname); + diary.retrieve(id).map_err_into(DEK::StoreReadError) + }; + + match entry { + Err(e) => trace_error_exit(&e, 1), + Ok(e) => { + debug!("Created: {}", e.get_location()); + e + } + } +} + + +fn create_id_from_clispec(create: &ArgMatches, diaryname: &str) -> DiaryId { + use std::str::FromStr; + + let get_hourly_id = |create: &ArgMatches| -> DiaryId { + let time = DiaryId::now(String::from(diaryname)); + let hr = create + .value_of("hour") + .map(|v| { debug!("Creating hourly entry with hour = {:?}", v); v }) + .and_then(|s| { + FromStr::from_str(s) + .map_err(|_| warn!("Could not parse hour: '{}'", s)) + .ok() + }) + .unwrap_or(time.hour()); + + time.with_hour(hr) + }; + + match create.value_of("timed") { + Some("h") | Some("hourly") => { + debug!("Creating hourly-timed entry"); + get_hourly_id(create) + }, + + Some("m") | Some("minutely") => { + let time = get_hourly_id(create); + let min = create + .value_of("minute") + .map(|m| { debug!("minute = {:?}", m); m }) + .and_then(|s| { + FromStr::from_str(s) + .map_err(|_| warn!("Could not parse minute: '{}'", s)) + .ok() + }) + .unwrap_or(time.minute()); + + time.with_minute(min) + }, + + Some(_) => { + warn!("Timed creation failed: Unknown spec '{}'", + create.value_of("timed").unwrap()); + exit(1); + }, + + None => warn_exit("Unexpected error, cannot continue", 1) + } +} + From 8071c4c72159e731c805770c64a8ef72f7651d94 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 29 Aug 2017 16:50:29 +0200 Subject: [PATCH 7/7] Refactor, minify edit() impl --- bin/domain/imag-diary/src/edit.rs | 53 +++++++++++++------------------ 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/bin/domain/imag-diary/src/edit.rs b/bin/domain/imag-diary/src/edit.rs index 3f9e59cf..c623e1fa 100644 --- a/bin/domain/imag-diary/src/edit.rs +++ b/bin/domain/imag-diary/src/edit.rs @@ -32,7 +32,6 @@ use libimagerror::into::IntoError; use libimagtimeui::datetime::DateTime; use libimagtimeui::parse::Parse; use libimagutil::warn_exit::warn_exit; -use libimagstore::storeid::IntoStoreId; use libimagerror::trace::trace_error_exit; use util::get_diary_name; @@ -40,40 +39,32 @@ use util::get_diary_name; pub fn edit(rt: &Runtime) { let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1)); - let datetime : Option = rt - .cli() + rt.cli() .subcommand_matches("edit") .unwrap() .value_of("datetime") .and_then(DateTime::parse) - .map(|dt| dt.into()); - - let to_edit = match datetime { - Some(dt) => { - let id = match DiaryId::from_datetime(diaryname.clone(), dt).into_storeid() { - Ok(id) => id, - Err(e) => trace_error_exit(&e, 1), - }; - rt.store().get(id) - }, - None => match rt.store().get_youngest_entry_id(&diaryname) { - Some(Ok(id)) => match id.into_storeid() { - Ok(sid) => rt.store().get(sid), - Err(e) => trace_error_exit(&e, 1), - }, - Some(Err(e)) => trace_error_exit(&e, 1), - None => { - error!("No entries in diary. Aborting"); - exit(1) - } - } - }; - - to_edit.map(|opte| match opte { - Some(mut e) => e.edit_content(rt).map_err_into(DEK::IOError), - None => Err(DEK::EntryNotInDiary.into_error()), - }) - .map_err_trace().ok(); + .map(|dt| dt.into()) + .map(|dt: NaiveDateTime| DiaryId::from_datetime(diaryname.clone(), dt)) + .or_else(|| { + rt.store() + .get_youngest_entry_id(&diaryname) + .map(|optid| match optid { + Ok(id) => id, + Err(e) => trace_error_exit(&e, 1), + }) + }) + .ok_or_else(|| { + error!("No entries in diary. Aborting"); + exit(1) + }) + .and_then(|id| rt.store().get(id)) + .map(|opte| match opte { + Some(mut e) => e.edit_content(rt).map_err_into(DEK::IOError), + None => Err(DEK::EntryNotInDiary.into_error()), + }) + .map_err_trace() + .ok(); }