Merge pull request #1031 from matthiasbeyer/libimagdiary/extension-as-trait
libimagdiary: extension as trait
This commit is contained in:
commit
1fe5a23331
11 changed files with 278 additions and 262 deletions
|
@ -19,16 +19,18 @@
|
||||||
|
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
|
use clap::ArgMatches;
|
||||||
|
|
||||||
use libimagdiary::diary::Diary;
|
use libimagdiary::diary::Diary;
|
||||||
use libimagdiary::diaryid::DiaryId;
|
use libimagdiary::diaryid::DiaryId;
|
||||||
use libimagdiary::error::DiaryErrorKind as DEK;
|
use libimagdiary::error::DiaryErrorKind as DEK;
|
||||||
use libimagdiary::error::MapErrInto;
|
use libimagdiary::error::MapErrInto;
|
||||||
use libimagentryedit::edit::Edit;
|
use libimagentryedit::edit::Edit;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagerror::trace::trace_error;
|
use libimagerror::trace::trace_error_exit;
|
||||||
use libimagdiary::entry::Entry;
|
|
||||||
use libimagdiary::result::Result;
|
|
||||||
use libimagutil::warn_exit::warn_exit;
|
use libimagutil::warn_exit::warn_exit;
|
||||||
|
use libimagstore::store::FileLockEntry;
|
||||||
|
use libimagstore::store::Store;
|
||||||
|
|
||||||
use util::get_diary_name;
|
use util::get_diary_name;
|
||||||
|
|
||||||
|
@ -36,20 +38,49 @@ pub fn create(rt: &Runtime) {
|
||||||
let diaryname = get_diary_name(rt)
|
let diaryname = get_diary_name(rt)
|
||||||
.unwrap_or_else( || warn_exit("No diary selected. Use either the configuration file or the commandline option", 1));
|
.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");
|
let mut entry = create_entry(rt.store(), &diaryname, rt);
|
||||||
|
|
||||||
fn create_entry<'a>(diary: &'a Diary, rt: &Runtime) -> Result<Entry<'a>> {
|
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)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = res {
|
||||||
|
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;
|
use std::str::FromStr;
|
||||||
|
|
||||||
let create = rt.cli().subcommand_matches("create").unwrap();
|
let get_hourly_id = |create: &ArgMatches| -> DiaryId {
|
||||||
if !create.is_present("timed") {
|
let time = DiaryId::now(String::from(diaryname));
|
||||||
debug!("Creating non-timed entry");
|
|
||||||
diary.new_entry_today()
|
|
||||||
} 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 hr = create
|
let hr = create
|
||||||
.value_of("hour")
|
.value_of("hour")
|
||||||
.map(|v| { debug!("Creating hourly entry with hour = {:?}", v); v })
|
.map(|v| { debug!("Creating hourly entry with hour = {:?}", v); v })
|
||||||
|
@ -60,22 +91,17 @@ pub fn create(rt: &Runtime) {
|
||||||
})
|
})
|
||||||
.unwrap_or(time.hour());
|
.unwrap_or(time.hour());
|
||||||
|
|
||||||
time.with_hour(hr).with_minute(0)
|
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") => {
|
Some("m") | Some("minutely") => {
|
||||||
debug!("Creating minutely-timed entry");
|
let time = get_hourly_id(create);
|
||||||
let time = DiaryId::now(String::from(diary.name()));
|
|
||||||
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
|
let min = create
|
||||||
.value_of("minute")
|
.value_of("minute")
|
||||||
.map(|m| { debug!("minute = {:?}", m); m })
|
.map(|m| { debug!("minute = {:?}", m); m })
|
||||||
|
@ -86,7 +112,7 @@ pub fn create(rt: &Runtime) {
|
||||||
})
|
})
|
||||||
.unwrap_or(time.minute());
|
.unwrap_or(time.minute());
|
||||||
|
|
||||||
time.with_hour(hr).with_minute(min)
|
time.with_minute(min)
|
||||||
},
|
},
|
||||||
|
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
|
@ -96,28 +122,6 @@ pub fn create(rt: &Runtime) {
|
||||||
},
|
},
|
||||||
|
|
||||||
None => warn_exit("Unexpected error, cannot continue", 1)
|
None => warn_exit("Unexpected error, cannot continue", 1)
|
||||||
};
|
|
||||||
|
|
||||||
diary.new_entry_by_id(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Err(e) = res {
|
|
||||||
trace_error(&e);
|
|
||||||
} else {
|
|
||||||
info!("Ok!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,15 +17,17 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
use chrono::naive::NaiveDateTime;
|
use chrono::naive::NaiveDateTime;
|
||||||
|
|
||||||
use libimagdiary::diary::Diary;
|
|
||||||
use libimagdiary::diaryid::DiaryId;
|
use libimagdiary::diaryid::DiaryId;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagerror::trace::trace_error_exit;
|
use libimagerror::trace::trace_error_exit;
|
||||||
use libimagtimeui::datetime::DateTime;
|
use libimagtimeui::datetime::DateTime;
|
||||||
use libimagtimeui::parse::Parse;
|
use libimagtimeui::parse::Parse;
|
||||||
use libimagutil::warn_exit::warn_exit;
|
use libimagutil::warn_exit::warn_exit;
|
||||||
|
use libimagstore::storeid::IntoStoreId;
|
||||||
|
|
||||||
use util::get_diary_name;
|
use util::get_diary_name;
|
||||||
|
|
||||||
|
@ -35,36 +37,34 @@ pub fn delete(rt: &Runtime) {
|
||||||
let diaryname = get_diary_name(rt)
|
let diaryname = get_diary_name(rt)
|
||||||
.unwrap_or_else(|| warn_exit("No diary selected. Use either the configuration file or the commandline option", 1));
|
.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[..]);
|
let to_del_location = rt
|
||||||
debug!("Diary opened: {:?}", diary);
|
|
||||||
|
|
||||||
let datetime : Option<NaiveDateTime> = rt
|
|
||||||
.cli()
|
.cli()
|
||||||
.subcommand_matches("delete")
|
.subcommand_matches("delete")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.value_of("datetime")
|
.value_of("datetime")
|
||||||
.map(|dt| { debug!("DateTime = {:?}", dt); dt })
|
.map(|dt| { debug!("DateTime = {:?}", dt); dt })
|
||||||
.and_then(DateTime::parse)
|
.and_then(DateTime::parse)
|
||||||
.map(|dt| dt.into());
|
.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 datetime {
|
if !ask_bool(&format!("Deleting {:?}", to_del_location), Some(true)) {
|
||||||
Some(dt) => Some(diary.retrieve(DiaryId::from_datetime(diaryname.clone(), dt))),
|
|
||||||
None => diary.get_youngest_entry(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let to_del = match to_del {
|
|
||||||
Some(Ok(e)) => e,
|
|
||||||
|
|
||||||
Some(Err(e)) => trace_error_exit(&e, 1),
|
|
||||||
None => warn_exit("No entry", 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !ask_bool(&format!("Deleting {:?}", to_del.get_location())[..], Some(true)) {
|
|
||||||
info!("Aborting delete action");
|
info!("Aborting delete action");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = diary.delete_entry(to_del) {
|
if let Err(e) = rt.store().delete(to_del_location) {
|
||||||
trace_error_exit(&e, 1)
|
trace_error_exit(&e, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
use chrono::naive::NaiveDateTime;
|
use chrono::naive::NaiveDateTime;
|
||||||
|
|
||||||
use libimagdiary::diary::Diary;
|
use libimagdiary::diary::Diary;
|
||||||
|
@ -30,33 +32,39 @@ use libimagerror::into::IntoError;
|
||||||
use libimagtimeui::datetime::DateTime;
|
use libimagtimeui::datetime::DateTime;
|
||||||
use libimagtimeui::parse::Parse;
|
use libimagtimeui::parse::Parse;
|
||||||
use libimagutil::warn_exit::warn_exit;
|
use libimagutil::warn_exit::warn_exit;
|
||||||
|
use libimagerror::trace::trace_error_exit;
|
||||||
|
|
||||||
use util::get_diary_name;
|
use util::get_diary_name;
|
||||||
|
|
||||||
pub fn edit(rt: &Runtime) {
|
pub fn edit(rt: &Runtime) {
|
||||||
let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1));
|
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<NaiveDateTime> = rt
|
rt.cli()
|
||||||
.cli()
|
|
||||||
.subcommand_matches("edit")
|
.subcommand_matches("edit")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.value_of("datetime")
|
.value_of("datetime")
|
||||||
.and_then(DateTime::parse)
|
.and_then(DateTime::parse)
|
||||||
.map(|dt| dt.into());
|
.map(|dt| dt.into())
|
||||||
|
.map(|dt: NaiveDateTime| DiaryId::from_datetime(diaryname.clone(), dt))
|
||||||
let to_edit = match datetime {
|
.or_else(|| {
|
||||||
Some(dt) => Some(diary.retrieve(DiaryId::from_datetime(diaryname.clone(), dt))),
|
rt.store()
|
||||||
None => diary.get_youngest_entry(),
|
.get_youngest_entry_id(&diaryname)
|
||||||
};
|
.map(|optid| match optid {
|
||||||
|
Ok(id) => id,
|
||||||
match to_edit {
|
Err(e) => trace_error_exit(&e, 1),
|
||||||
Some(Ok(mut e)) => e.edit_content(rt).map_err_into(DEK::IOError),
|
})
|
||||||
|
})
|
||||||
Some(Err(e)) => Err(e),
|
.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()),
|
None => Err(DEK::EntryNotInDiary.into_error()),
|
||||||
}
|
})
|
||||||
.map_err_trace().ok();
|
.map_err_trace()
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,9 +42,7 @@ pub fn list(rt: &Runtime) {
|
||||||
.unwrap_or(String::from("<<Path Parsing Error>>"))
|
.unwrap_or(String::from("<<Path Parsing Error>>"))
|
||||||
}
|
}
|
||||||
|
|
||||||
let diary = Diary::open(rt.store(), &diaryname[..]);
|
Diary::entries(rt.store(), &diaryname)
|
||||||
debug!("Diary opened: {:?}", diary);
|
|
||||||
diary.entries()
|
|
||||||
.and_then(|es| {
|
.and_then(|es| {
|
||||||
debug!("Iterator for listing: {:?}", es);
|
debug!("Iterator for listing: {:?}", es);
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,9 @@ use util::get_diary_name;
|
||||||
|
|
||||||
pub fn view(rt: &Runtime) {
|
pub fn view(rt: &Runtime) {
|
||||||
let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1));
|
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");
|
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)))
|
.and_then(|entries| DV::new(hdr).view_entries(entries.into_iter().filter_map(Result::ok)))
|
||||||
.map_err_trace()
|
.map_err_trace()
|
||||||
.ok();
|
.ok();
|
||||||
|
|
|
@ -19,85 +19,85 @@
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::storeid::IntoStoreId;
|
|
||||||
use libimagerror::trace::trace_error;
|
use libimagerror::trace::trace_error;
|
||||||
|
|
||||||
use chrono::offset::Local;
|
use chrono::offset::Local;
|
||||||
use chrono::Datelike;
|
use chrono::Datelike;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use chrono::naive::NaiveDateTime;
|
use chrono::naive::NaiveDateTime;
|
||||||
|
use chrono::Timelike;
|
||||||
|
|
||||||
use entry::Entry;
|
use entry::DiaryEntry;
|
||||||
use diaryid::DiaryId;
|
use diaryid::DiaryId;
|
||||||
use error::DiaryError as DE;
|
|
||||||
use error::DiaryErrorKind as DEK;
|
use error::DiaryErrorKind as DEK;
|
||||||
|
use error::MapErrInto;
|
||||||
use result::Result;
|
use result::Result;
|
||||||
use iter::DiaryEntryIterator;
|
use iter::DiaryEntryIterator;
|
||||||
use is_in_diary::IsInDiary;
|
use iter::DiaryNameIterator;
|
||||||
|
|
||||||
|
pub trait Diary {
|
||||||
|
|
||||||
|
// create or get a new entry for today
|
||||||
|
fn new_entry_today(&self, diary_name: &str) -> Result<FileLockEntry>;
|
||||||
|
|
||||||
|
// create or get a new entry for now
|
||||||
|
fn new_entry_now(&self, diary_name: &str) -> Result<FileLockEntry>;
|
||||||
|
|
||||||
|
// Get an iterator for iterating over all entries of a Diary
|
||||||
|
fn entries(&self, diary_name: &str) -> Result<DiaryEntryIterator>;
|
||||||
|
|
||||||
|
fn get_youngest_entry_id(&self, diary_name: &str) -> Option<Result<DiaryId>>;
|
||||||
|
|
||||||
|
/// Get all diary names
|
||||||
|
fn diary_names(&self) -> Result<DiaryNameIterator>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Diary<'a> {
|
|
||||||
store: &'a Store,
|
|
||||||
name: &'a str,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Diary<'a> {
|
impl Diary for Store {
|
||||||
|
|
||||||
pub fn open(store: &'a Store, name: &'a str) -> Diary<'a> {
|
// create or get a new entry for today
|
||||||
Diary {
|
fn new_entry_today(&self, diary_name: &str) -> Result<FileLockEntry> {
|
||||||
store: store,
|
let dt = Local::now();
|
||||||
name: name,
|
let ndt = dt.naive_local();
|
||||||
}
|
let id = DiaryId::new(String::from(diary_name), ndt.year(), ndt.month(), ndt.day(), 0, 0);
|
||||||
|
|
||||||
|
self.retrieve(id).map_err_into(DEK::StoreReadError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create or get a new entry for today
|
// create or get a new entry for today
|
||||||
pub fn new_entry_today(&self) -> Result<Entry> {
|
fn new_entry_now(&self, diary_name: &str) -> Result<FileLockEntry> {
|
||||||
let dt = Local::now();
|
let dt = Local::now();
|
||||||
let ndt = dt.naive_local();
|
let ndt = dt.naive_local();
|
||||||
let id = DiaryId::new(String::from(self.name), ndt.year(), ndt.month(), ndt.day(), 0, 0);
|
let id = DiaryId::new(String::from(diary_name),
|
||||||
self.new_entry_by_id(id)
|
ndt.year(),
|
||||||
}
|
ndt.month(),
|
||||||
|
ndt.day(),
|
||||||
|
ndt.minute(),
|
||||||
|
ndt.second());
|
||||||
|
|
||||||
pub fn new_entry_by_id(&self, id: DiaryId) -> Result<Entry> {
|
self.retrieve(id).map_err_into(DEK::StoreReadError)
|
||||||
self.retrieve(id.with_diary_name(String::from(self.name)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn retrieve(&self, id: DiaryId) -> Result<Entry> {
|
|
||||||
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
|
// Get an iterator for iterating over all entries
|
||||||
pub fn entries(&self) -> Result<DiaryEntryIterator<'a>> {
|
fn entries(&self, diary_name: &str) -> Result<DiaryEntryIterator> {
|
||||||
self.store
|
self.retrieve_for_module("diary")
|
||||||
.retrieve_for_module("diary")
|
.map(|iter| DiaryEntryIterator::new(self, String::from(diary_name), iter))
|
||||||
.map(|iter| DiaryEntryIterator::new(self.name, self.store, iter))
|
.map_err_into(DEK::StoreReadError)
|
||||||
.map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_entry(&self, entry: Entry) -> Result<()> {
|
fn get_youngest_entry_id(&self, diary_name: &str) -> Option<Result<DiaryId>> {
|
||||||
if !entry.is_in_diary(self.name) {
|
match Diary::entries(self, diary_name) {
|
||||||
return Err(DE::new(DEK::EntryNotInDiary, None));
|
|
||||||
}
|
|
||||||
let id = entry.get_location().clone();
|
|
||||||
drop(entry);
|
|
||||||
|
|
||||||
self.store.delete(id)
|
|
||||||
.map_err(|e| DE::new(DEK::StoreWriteError, Some(Box::new(e))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_youngest_entry(&self) -> Option<Result<Entry>> {
|
|
||||||
match self.entries() {
|
|
||||||
Err(e) => Some(Err(e)),
|
Err(e) => Some(Err(e)),
|
||||||
Ok(entries) => {
|
Ok(entries) => {
|
||||||
entries.sorted_by(|a, b| {
|
entries
|
||||||
|
.map(|e| e.and_then(|e| e.diary_id()))
|
||||||
|
.sorted_by(|a, b| {
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(&Ok(ref a), &Ok(ref b)) => {
|
(&Ok(ref a), &Ok(ref b)) => {
|
||||||
let a : NaiveDateTime = a.diary_id().into();
|
let a : NaiveDateTime = a.clone().into();
|
||||||
let b : NaiveDateTime = b.diary_id().into();
|
let b : NaiveDateTime = b.clone().into();
|
||||||
|
|
||||||
a.cmp(&b)
|
a.cmp(&b)
|
||||||
},
|
},
|
||||||
|
@ -116,13 +116,20 @@ impl<'a> Diary<'a> {
|
||||||
Ordering::Equal
|
Ordering::Equal
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}).into_iter().next()
|
})
|
||||||
|
.into_iter()
|
||||||
|
//.map(|sidres| sidres.map(|sid| DiaryId::from_storeid(&sid)))
|
||||||
|
.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &'a str {
|
/// Get all diary names
|
||||||
&self.name
|
fn diary_names(&self) -> Result<DiaryNameIterator> {
|
||||||
|
self.retrieve_for_module("diary")
|
||||||
|
.map_err_into(DEK::StoreReadError)
|
||||||
|
.map(DiaryNameIterator::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,74 +17,24 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
use std::ops::Deref;
|
use libimagstore::store::Entry;
|
||||||
use std::ops::DerefMut;
|
|
||||||
|
|
||||||
use libimagstore::store::FileLockEntry;
|
|
||||||
use libimagentryedit::edit::Edit;
|
|
||||||
use libimagentryedit::result::Result as EditResult;
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
|
|
||||||
use diaryid::DiaryId;
|
use diaryid::DiaryId;
|
||||||
use diaryid::FromStoreId;
|
use diaryid::FromStoreId;
|
||||||
|
use result::Result;
|
||||||
|
|
||||||
#[derive(Debug)]
|
pub trait DiaryEntry {
|
||||||
pub struct Entry<'a>(FileLockEntry<'a>);
|
fn diary_id(&self) -> Result<DiaryId>;
|
||||||
|
|
||||||
impl<'a> Deref for Entry<'a> {
|
|
||||||
type Target = FileLockEntry<'a>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &FileLockEntry<'a> {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DerefMut for Entry<'a> {
|
impl DiaryEntry for Entry {
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the diary id for this 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
|
/// TODO: calls Option::unwrap() as it assumes that an existing Entry has an ID that is parsable
|
||||||
pub fn diary_id(&self) -> DiaryId {
|
fn diary_id(&self) -> Result<DiaryId> {
|
||||||
DiaryId::from_storeid(&self.0.get_location().clone()).unwrap()
|
DiaryId::from_storeid(&self.get_location().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Into<FileLockEntry<'a>> for Entry<'a> {
|
|
||||||
|
|
||||||
fn into(self) -> FileLockEntry<'a> {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<FileLockEntry<'a>> 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ generate_error_module!(
|
||||||
EntryNotInDiary => "Entry not in Diary",
|
EntryNotInDiary => "Entry not in Diary",
|
||||||
IOError => "IO Error",
|
IOError => "IO Error",
|
||||||
ViewError => "Error viewing diary entry",
|
ViewError => "Error viewing diary entry",
|
||||||
IdParseError => "Error while parsing ID"
|
IdParseError => "Error while parsing ID",
|
||||||
|
DiaryNameFindingError => "Error while finding a diary name"
|
||||||
);
|
);
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ pub trait IsInDiary {
|
||||||
|
|
||||||
fn is_in_diary(&self, name: &str) -> bool;
|
fn is_in_diary(&self, name: &str) -> bool;
|
||||||
|
|
||||||
|
fn is_a_diary_entry(&self) -> bool;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IsInDiary for Entry {
|
impl IsInDiary for Entry {
|
||||||
|
@ -32,6 +34,10 @@ impl IsInDiary for Entry {
|
||||||
self.get_location().clone().is_in_diary(name)
|
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 {
|
impl IsInDiary for StoreId {
|
||||||
|
@ -40,5 +46,9 @@ impl IsInDiary for StoreId {
|
||||||
self.local().starts_with(format!("diary/{}", name))
|
self.local().starts_with(format!("diary/{}", name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_a_diary_entry(&self) -> bool {
|
||||||
|
self.local().starts_with("diary")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,21 +21,23 @@ use std::fmt::{Debug, Formatter, Error as FmtError};
|
||||||
use std::result::Result as RResult;
|
use std::result::Result as RResult;
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
use libimagstore::storeid::StoreIdIterator;
|
||||||
|
use libimagerror::trace::trace_error;
|
||||||
|
use libimagerror::into::IntoError;
|
||||||
|
|
||||||
use diaryid::DiaryId;
|
use diaryid::DiaryId;
|
||||||
use diaryid::FromStoreId;
|
use diaryid::FromStoreId;
|
||||||
use is_in_diary::IsInDiary;
|
|
||||||
use entry::Entry as DiaryEntry;
|
|
||||||
use error::DiaryError as DE;
|
use error::DiaryError as DE;
|
||||||
use error::DiaryErrorKind as DEK;
|
use error::DiaryErrorKind as DEK;
|
||||||
|
use error::MapErrInto;
|
||||||
use result::Result;
|
use result::Result;
|
||||||
use libimagerror::trace::trace_error;
|
use is_in_diary::IsInDiary;
|
||||||
|
|
||||||
/// A iterator for iterating over diary entries
|
/// A iterator for iterating over diary entries
|
||||||
pub struct DiaryEntryIterator<'a> {
|
pub struct DiaryEntryIterator<'a> {
|
||||||
store: &'a Store,
|
store: &'a Store,
|
||||||
name: &'a str,
|
name: String,
|
||||||
iter: StoreIdIterator,
|
iter: StoreIdIterator,
|
||||||
|
|
||||||
year: Option<i32>,
|
year: Option<i32>,
|
||||||
|
@ -54,7 +56,7 @@ impl<'a> Debug for DiaryEntryIterator<'a> {
|
||||||
|
|
||||||
impl<'a> 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 {
|
DiaryEntryIterator {
|
||||||
store: store,
|
store: store,
|
||||||
name: diaryname,
|
name: diaryname,
|
||||||
|
@ -87,9 +89,9 @@ impl<'a> DiaryEntryIterator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for DiaryEntryIterator<'a> {
|
impl<'a> Iterator for DiaryEntryIterator<'a> {
|
||||||
type Item = Result<DiaryEntry<'a>>;
|
type Item = Result<FileLockEntry<'a>>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Result<DiaryEntry<'a>>> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
loop {
|
loop {
|
||||||
let next = match self.iter.next() {
|
let next = match self.iter.next() {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
|
@ -97,7 +99,7 @@ impl<'a> Iterator for DiaryEntryIterator<'a> {
|
||||||
};
|
};
|
||||||
debug!("Next element: {:?}", next);
|
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);
|
debug!("Seems to be in diary: {:?}", next);
|
||||||
let id = match DiaryId::from_storeid(&next) {
|
let id = match DiaryId::from_storeid(&next) {
|
||||||
Ok(i) => i,
|
Ok(i) => i,
|
||||||
|
@ -118,7 +120,6 @@ impl<'a> Iterator for DiaryEntryIterator<'a> {
|
||||||
return Some(self
|
return Some(self
|
||||||
.store
|
.store
|
||||||
.retrieve(next)
|
.retrieve(next)
|
||||||
.map(|fle| DiaryEntry::new(fle))
|
|
||||||
.map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e))))
|
.map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e))))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -130,3 +131,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<String>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
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())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,13 +19,15 @@
|
||||||
|
|
||||||
//! A diary viewer built on libimagentryview.
|
//! A diary viewer built on libimagentryview.
|
||||||
|
|
||||||
use entry::Entry;
|
use entry::DiaryEntry;
|
||||||
use error::DiaryErrorKind as DEK;
|
use error::DiaryErrorKind as DEK;
|
||||||
use error::MapErrInto;
|
use error::MapErrInto;
|
||||||
use result::Result;
|
use result::Result;
|
||||||
|
|
||||||
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagentryview::viewer::Viewer;
|
use libimagentryview::viewer::Viewer;
|
||||||
use libimagentryview::builtin::plain::PlainViewer;
|
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
|
/// 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.
|
/// call some diary-type specific functions on the entries passed to this.
|
||||||
|
@ -46,10 +48,12 @@ impl DiaryViewer {
|
||||||
|
|
||||||
/// View all entries from the iterator, or stop immediately if an error occurs, returning that
|
/// View all entries from the iterator, or stop immediately if an error occurs, returning that
|
||||||
/// error.
|
/// error.
|
||||||
pub fn view_entries<'a, I: Iterator<Item = Entry<'a>>>(&self, entries: I) -> Result<()> {
|
pub fn view_entries<'a, I: Iterator<Item = FileLockEntry<'a>>>(&self, entries: I) -> Result<()> {
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
let id = entry.diary_id();
|
match entry.diary_id() {
|
||||||
println!("{} :\n", id);
|
Ok(id) => println!("{} :\n", id),
|
||||||
|
Err(e) => trace_error(&e),
|
||||||
|
}
|
||||||
let _ = try!(self.0
|
let _ = try!(self.0
|
||||||
.view_entry(&entry)
|
.view_entry(&entry)
|
||||||
.map_err_into(DEK::ViewError)
|
.map_err_into(DEK::ViewError)
|
||||||
|
|
Loading…
Reference in a new issue