Implement Diary as trait
This commit is contained in:
parent
22de22e6e5
commit
9c69645b69
5 changed files with 154 additions and 77 deletions
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
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 libimagstore::storeid::IntoStoreId;
|
||||||
use libimagerror::trace::trace_error;
|
use libimagerror::trace::trace_error;
|
||||||
|
@ -27,102 +28,136 @@ 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::Entry;
|
||||||
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;
|
||||||
|
|
||||||
#[derive(Debug)]
|
trait Diary {
|
||||||
pub struct Diary<'a> {
|
|
||||||
store: &'a Store,
|
|
||||||
name: &'a str,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Diary<'a> {
|
/// Wrapper around Store::get for DiaryId
|
||||||
|
fn get(&self, id: DiaryId) -> Result<Option<FileLockEntry>>;
|
||||||
|
|
||||||
pub fn open(store: &'a Store, name: &'a str) -> Diary<'a> {
|
/// Wrapper around Store::retrieve for DiaryId
|
||||||
Diary {
|
fn retrieve(&self, id: DiaryId) -> Result<FileLockEntry>;
|
||||||
store: store,
|
|
||||||
name: name,
|
/// Wrapper around Store::delete for DiaryId
|
||||||
}
|
fn delete(&self, entry: Entry) -> Result<()>;
|
||||||
}
|
|
||||||
|
|
||||||
// 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_today(&self, diary_name: &str) -> Result<FileLockEntry>;
|
||||||
let dt = Local::now();
|
|
||||||
let ndt = dt.naive_local();
|
// create or get a new entry for now
|
||||||
let id = DiaryId::new(String::from(self.name), ndt.year(), ndt.month(), ndt.day(), 0, 0);
|
fn new_entry_now(&self, diary_name: &str) -> Result<FileLockEntry>;
|
||||||
self.new_entry_by_id(id)
|
|
||||||
|
// 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>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Diary for Store {
|
||||||
|
|
||||||
|
|
||||||
|
/// Wrapper around Store::get for DiaryId
|
||||||
|
fn get(&self, id: DiaryId) -> Result<Option<FileLockEntry>> {
|
||||||
|
id.into_storeid().and_then(|id| self.get(id)).map_err_into(DEK::StoreWriteError)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_entry_by_id(&self, id: DiaryId) -> Result<Entry> {
|
/// Wrapper around Store::retrieve for DiaryId
|
||||||
self.retrieve(id.with_diary_name(String::from(self.name)))
|
fn retrieve(&self, id: DiaryId) -> Result<FileLockEntry> {
|
||||||
|
id.into_storeid().and_then(|id| self.retrieve(id)).map_err_into(DEK::StoreWriteError)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn retrieve(&self, id: DiaryId) -> Result<Entry> {
|
/// Wrapper around Store::delete for DiaryId
|
||||||
id.into_storeid()
|
fn delete(&self, entry: Entry) -> Result<()> {
|
||||||
.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<DiaryEntryIterator<'a>> {
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
let id = entry.get_location().clone();
|
let id = entry.get_location().clone();
|
||||||
drop(entry);
|
drop(entry);
|
||||||
|
|
||||||
self.store.delete(id)
|
self.delete(id).map_err_into(DEK::StoreWriteError)
|
||||||
.map_err(|e| DE::new(DEK::StoreWriteError, Some(Box::new(e))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_youngest_entry(&self) -> Option<Result<Entry>> {
|
// create or get a new entry for today
|
||||||
match self.entries() {
|
fn new_entry_today(&self, diary_name: &str) -> Result<FileLockEntry> {
|
||||||
|
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<FileLockEntry> {
|
||||||
|
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<DiaryEntryIterator> {
|
||||||
|
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<Result<DiaryId>> {
|
||||||
|
match Diary::entries(self, diary_name) {
|
||||||
Err(e) => Some(Err(e)),
|
Err(e) => Some(Err(e)),
|
||||||
Ok(entries) => {
|
Ok(entries) => {
|
||||||
entries.sorted_by(|a, b| {
|
entries
|
||||||
match (a, b) {
|
.map(|e| e.and_then(|e| e.diary_id()))
|
||||||
(&Ok(ref a), &Ok(ref b)) => {
|
.sorted_by(|a, b| {
|
||||||
let a : NaiveDateTime = a.diary_id().into();
|
match (a, b) {
|
||||||
let b : NaiveDateTime = b.diary_id().into();
|
(&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)) => {
|
(&Ok(_), &Err(ref e)) => {
|
||||||
trace_error(e);
|
trace_error(e);
|
||||||
Ordering::Less
|
Ordering::Less
|
||||||
},
|
},
|
||||||
(&Err(ref e), &Ok(_)) => {
|
(&Err(ref e), &Ok(_)) => {
|
||||||
trace_error(e);
|
trace_error(e);
|
||||||
Ordering::Greater
|
Ordering::Greater
|
||||||
},
|
},
|
||||||
(&Err(ref e1), &Err(ref e2)) => {
|
(&Err(ref e1), &Err(ref e2)) => {
|
||||||
trace_error(e1);
|
trace_error(e1);
|
||||||
trace_error(e2);
|
trace_error(e2);
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ use libimagrt::runtime::Runtime;
|
||||||
|
|
||||||
use diaryid::DiaryId;
|
use diaryid::DiaryId;
|
||||||
use diaryid::FromStoreId;
|
use diaryid::FromStoreId;
|
||||||
|
use result::Result;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Entry<'a>(FileLockEntry<'a>);
|
pub struct Entry<'a>(FileLockEntry<'a>);
|
||||||
|
@ -57,8 +58,8 @@ impl<'a> Entry<'a> {
|
||||||
/// 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 {
|
pub fn diary_id(&self) -> Result<DiaryId> {
|
||||||
DiaryId::from_storeid(&self.0.get_location().clone()).unwrap()
|
DiaryId::from_storeid(&self.0.get_location().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
);
|
);
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ use std::result::Result as RResult;
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
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;
|
||||||
|
@ -29,13 +31,14 @@ use is_in_diary::IsInDiary;
|
||||||
use entry::Entry as DiaryEntry;
|
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 +57,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,
|
||||||
|
@ -97,7 +100,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,
|
||||||
|
@ -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<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())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ use result::Result;
|
||||||
|
|
||||||
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.
|
||||||
|
@ -48,8 +49,10 @@ impl DiaryViewer {
|
||||||
/// error.
|
/// error.
|
||||||
pub fn view_entries<'a, I: Iterator<Item = Entry<'a>>>(&self, entries: I) -> Result<()> {
|
pub fn view_entries<'a, I: Iterator<Item = Entry<'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