From 94855fb7225f555a61285b5c41f97f9da636fe66 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 14 Sep 2017 19:43:51 +0200 Subject: [PATCH 1/4] Refactor libimagdiary To not wrap types anymore, but rather use extension traits for extending all the things. --- lib/domain/libimagnotes/src/iter.rs | 50 +++++++ lib/domain/libimagnotes/src/lib.rs | 3 + lib/domain/libimagnotes/src/note.rs | 164 ++------------------- lib/domain/libimagnotes/src/notestore.rs | 108 ++++++++++++++ lib/domain/libimagnotes/src/notestoreid.rs | 32 ++++ 5 files changed, 208 insertions(+), 149 deletions(-) create mode 100644 lib/domain/libimagnotes/src/iter.rs create mode 100644 lib/domain/libimagnotes/src/notestore.rs create mode 100644 lib/domain/libimagnotes/src/notestoreid.rs diff --git a/lib/domain/libimagnotes/src/iter.rs b/lib/domain/libimagnotes/src/iter.rs new file mode 100644 index 00000000..ec7191f3 --- /dev/null +++ b/lib/domain/libimagnotes/src/iter.rs @@ -0,0 +1,50 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use libimagstore::storeid::StoreId; +use libimagstore::storeid::StoreIdIterator; + +use notestoreid::*; + +#[derive(Debug)] +pub struct NoteIterator(StoreIdIterator); + +impl NoteIterator { + + pub fn new(iditer: StoreIdIterator) -> NoteIterator { + NoteIterator(iditer) + } + +} + +impl Iterator for NoteIterator { + type Item = StoreId; + + fn next(&mut self) -> Option { + while let Some(n) = self.0.next() { + if n.is_note_id() { + return Some(n); + } + } + + None + } + +} + diff --git a/lib/domain/libimagnotes/src/lib.rs b/lib/domain/libimagnotes/src/lib.rs index 6d2fbba4..7dc761be 100644 --- a/lib/domain/libimagnotes/src/lib.rs +++ b/lib/domain/libimagnotes/src/lib.rs @@ -49,4 +49,7 @@ module_entry_path_mod!("notes"); pub mod error; pub mod note; +pub mod notestore; +pub mod notestoreid; +pub mod iter; diff --git a/lib/domain/libimagnotes/src/note.rs b/lib/domain/libimagnotes/src/note.rs index 599a0db6..f7b0ed77 100644 --- a/lib/domain/libimagnotes/src/note.rs +++ b/lib/domain/libimagnotes/src/note.rs @@ -17,80 +17,36 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // -use std::collections::BTreeMap; -use std::ops::Deref; - use toml::Value; -use libimagrt::runtime::Runtime; -use libimagentryedit::edit::Edit; -use libimagentryedit::error::Result as EditResult; -use libimagstore::storeid::IntoStoreId; -use libimagstore::storeid::StoreId; -use libimagstore::storeid::StoreIdIterator; -use libimagstore::store::FileLockEntry; -use libimagstore::store::Store; +use libimagstore::store::Entry; use toml_query::read::TomlValueReadExt; use toml_query::set::TomlValueSetExt; -use module_path::ModuleEntryPath; use error::Result; use error::NoteErrorKind as NEK; use error::NoteError as NE; use error::ResultExt; -#[derive(Debug)] -pub struct Note<'a> { - entry: FileLockEntry<'a>, +pub trait Note { + fn set_name(&mut self, n: String) -> Result<()>; + fn get_name(&self) -> Result; + fn set_text(&mut self, n: String); + fn get_text(&self) -> &String; } -impl<'a> Note<'a> { +impl Note for Entry { - pub fn new(store: &Store, name: String, text: String) -> Result { - use std::ops::DerefMut; - - debug!("Creating new Note: '{}'", name); - let fle = { - let mut lockentry = try!(ModuleEntryPath::new(name.clone()) - .into_storeid() - .and_then(|id| store.create(id)) - .chain_err(|| NEK::StoreWriteError)); - - { - let entry = lockentry.deref_mut(); - - { - let header = entry.get_header_mut(); - let _ = header - .set("note", Value::Table(BTreeMap::new())) - .chain_err(|| NEK::StoreWriteError); - - let _ = header - .set("note.name", Value::String(name)) - .chain_err(|| NEK::StoreWriteError); - } - - *entry.get_content_mut() = text; - } - - lockentry - }; - - Ok(Note { entry: fle }) - } - - pub fn set_name(&mut self, n: String) -> Result<()> { - self.entry - .get_header_mut() + fn set_name(&mut self, n: String) -> Result<()> { + self.get_header_mut() .set("note.name", Value::String(n)) .chain_err(|| NEK::StoreWriteError) .map(|_| ()) } - pub fn get_name(&self) -> Result { - let header = self.entry.get_header(); - match header.read("note.name") { + fn get_name(&self) -> Result { + match self.get_header().read("note.name") { Ok(Some(&Value::String(ref s))) => Ok(s.clone()), Ok(_) => { Err(NE::from_kind(NEK::HeaderTypeError)).chain_err(|| NEK::StoreReadError) @@ -99,104 +55,14 @@ impl<'a> Note<'a> { } } - pub fn set_text(&mut self, n: String) { - *self.entry.get_content_mut() = n + fn set_text(&mut self, n: String) { + *self.get_content_mut() = n } - pub fn get_text(&self) -> &String { - self.entry.get_content() - } - - pub fn delete(store: &Store, name: String) -> Result<()> { - ModuleEntryPath::new(name) - .into_storeid() - .and_then(|id| store.delete(id)) - .chain_err(|| NEK::StoreWriteError) - } - - pub fn retrieve(store: &Store, name: String) -> Result { - ModuleEntryPath::new(name) - .into_storeid() - .and_then(|id| store.retrieve(id)) - .chain_err(|| NEK::StoreWriteError) - .map(|entry| Note { entry: entry }) - } - - pub fn get(store: &Store, name: String) -> Result> { - ModuleEntryPath::new(name) - .into_storeid() - .and_then(|id| store.get(id)) - .chain_err(|| NEK::StoreWriteError) - .map(|o| o.map(|entry| Note { entry: entry })) - } - - pub fn all_notes(store: &Store) -> Result { - store.retrieve_for_module("notes") - .map(|iter| NoteIterator::new(store, iter)) - .chain_err(|| NEK::StoreReadError) + fn get_text(&self) -> &String { + self.get_content() } } -impl<'a> Edit for Note<'a> { - - fn edit_content(&mut self, rt: &Runtime) -> EditResult<()> { - self.entry.edit_content(rt) - } - -} - -trait FromStoreId { - fn from_storeid(&Store, StoreId) -> Result; -} - -impl<'a> FromStoreId for Note<'a> { - - fn from_storeid(store: &Store, id: StoreId) -> Result { - debug!("Loading note from storeid: '{:?}'", id); - match store.retrieve(id) { - Err(e) => Err(e).chain_err(|| NEK::StoreReadError), - Ok(entry) => Ok(Note { entry: entry }), - } - } - -} - -impl<'a> Deref for Note<'a> { - - type Target = FileLockEntry<'a>; - - fn deref(&self) -> &FileLockEntry<'a> { - &self.entry - } - -} - -#[derive(Debug)] -pub struct NoteIterator<'a> { - store: &'a Store, - iditer: StoreIdIterator, -} - -impl<'a> NoteIterator<'a> { - - pub fn new(store: &'a Store, iditer: StoreIdIterator) -> NoteIterator<'a> { - NoteIterator { - store: store, - iditer: iditer, - } - } - -} - -impl<'a> Iterator for NoteIterator<'a> { - type Item = Result>; - - fn next(&mut self) -> Option>> { - self.iditer - .next() - .map(|id| Note::from_storeid(self.store, id)) - } - -} diff --git a/lib/domain/libimagnotes/src/notestore.rs b/lib/domain/libimagnotes/src/notestore.rs new file mode 100644 index 00000000..b16de614 --- /dev/null +++ b/lib/domain/libimagnotes/src/notestore.rs @@ -0,0 +1,108 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use std::collections::BTreeMap; + +use toml::Value; + +use libimagstore::storeid::IntoStoreId; +use libimagstore::store::FileLockEntry; +use libimagstore::store::Store; + +use toml_query::set::TomlValueSetExt; + +use module_path::ModuleEntryPath; +use error::Result; +use error::NoteErrorKind as NEK; +use error::ResultExt; +use iter::*; + +pub trait NoteStore<'a> { + fn new_note(&'a self, name: String, text: String) -> Result>; + fn delete_note(&'a self, name: String) -> Result<()>; + fn retrieve_note(&'a self, name: String) -> Result>; + fn get_note(&'a self, name: String) -> Result>>; + fn all_notes(&'a self) -> Result; +} + + +impl<'a> NoteStore<'a> for Store { + + fn new_note(&'a self, name: String, text: String) -> Result> { + use std::ops::DerefMut; + + debug!("Creating new Note: '{}'", name); + let fle = { + let mut lockentry = try!(ModuleEntryPath::new(name.clone()) + .into_storeid() + .and_then(|id| self.create(id)) + .chain_err(|| NEK::StoreWriteError)); + + { + let entry = lockentry.deref_mut(); + + { + let header = entry.get_header_mut(); + let _ = header + .set("note", Value::Table(BTreeMap::new())) + .chain_err(|| NEK::StoreWriteError); + + let _ = header + .set("note.name", Value::String(name)) + .chain_err(|| NEK::StoreWriteError); + } + + *entry.get_content_mut() = text; + } + + lockentry + }; + + Ok(fle) + } + + fn delete_note(&'a self, name: String) -> Result<()> { + ModuleEntryPath::new(name) + .into_storeid() + .and_then(|id| self.delete(id)) + .chain_err(|| NEK::StoreWriteError) + } + + fn retrieve_note(&'a self, name: String) -> Result> { + ModuleEntryPath::new(name) + .into_storeid() + .and_then(|id| self.retrieve(id)) + .chain_err(|| NEK::StoreWriteError) + } + + fn get_note(&'a self, name: String) -> Result>> { + ModuleEntryPath::new(name) + .into_storeid() + .and_then(|id| self.get(id)) + .chain_err(|| NEK::StoreWriteError) + } + + fn all_notes(&'a self) -> Result { + self.retrieve_for_module("notes") + .map(NoteIterator::new) + .chain_err(|| NEK::StoreReadError) + } + +} + diff --git a/lib/domain/libimagnotes/src/notestoreid.rs b/lib/domain/libimagnotes/src/notestoreid.rs new file mode 100644 index 00000000..680eacd7 --- /dev/null +++ b/lib/domain/libimagnotes/src/notestoreid.rs @@ -0,0 +1,32 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use libimagstore::storeid::StoreId; + +pub trait NoteStoreId { + fn is_note_id(&self) -> bool; +} + +impl NoteStoreId for StoreId { + fn is_note_id(&self) -> bool { + self.is_in_collection(&["notes"]) + } +} + + From 2bbda59051133e66182e3af1952b8787afea09a8 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 14 Sep 2017 19:57:48 +0200 Subject: [PATCH 2/4] Refactor and simplify imag-notes binary --- bin/domain/imag-notes/src/main.rs | 65 +++++++++++++++++-------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/bin/domain/imag-notes/src/main.rs b/bin/domain/imag-notes/src/main.rs index 83c54fab..86dfe962 100644 --- a/bin/domain/imag-notes/src/main.rs +++ b/bin/domain/imag-notes/src/main.rs @@ -28,18 +28,18 @@ extern crate libimagentryedit; extern crate libimagerror; extern crate libimagutil; -use std::process::exit; - use itertools::Itertools; use libimagentryedit::edit::Edit; use libimagrt::runtime::Runtime; use libimagrt::setup::generate_runtime_setup; use libimagnotes::note::Note; -use libimagerror::trace::{MapErrTrace, trace_error}; +use libimagnotes::notestore::*; +use libimagerror::trace::MapErrTrace; use libimagutil::info_result::*; use libimagutil::warn_result::WarnResult; + mod ui; use ui::build_ui; @@ -71,49 +71,54 @@ fn name_from_cli(rt: &Runtime, subcmd: &str) -> String { fn create(rt: &Runtime) { let name = name_from_cli(rt, "create"); - Note::new(rt.store(), name.clone(), String::new()).map_err_trace().ok(); + let mut note = rt + .store() + .new_note(name.clone(), String::new()) + .map_err_trace_exit(1) + .unwrap(); - if rt.cli().subcommand_matches("create").unwrap().is_present("edit") && - !edit_entry(rt, name) { - exit(1); + if rt.cli().subcommand_matches("create").unwrap().is_present("edit") { + let _ = note + .edit_content(rt) + .map_warn_err_str("Editing failed") + .map_err_trace_exit(1); } } fn delete(rt: &Runtime) { - Note::delete(rt.store(), String::from(name_from_cli(rt, "delete"))) - .map_err_trace() + let _ = rt.store() + .delete_note(name_from_cli(rt, "delete")) .map_info_str("Ok") - .ok(); + .map_err_trace_exit(1); } fn edit(rt: &Runtime) { - edit_entry(rt, name_from_cli(rt, "edit")); -} - -fn edit_entry(rt: &Runtime, name: String) -> bool { - let mut note = match Note::get(rt.store(), name) { - Ok(Some(note)) => note, - Ok(None) => { - warn!("Cannot edit nonexistent Note"); - return false - }, - Err(e) => { - trace_error(&e); - warn!("Cannot edit nonexistent Note"); - return false - }, - }; - - note.edit_content(rt).map_err_trace().map_warn_err_str("Editing failed").is_ok() + let name = name_from_cli(rt, "edit"); + let _ = rt + .store() + .get_note(name.clone()) + .map_err_trace_exit(1) + .unwrap() + .map(|mut note| { + let _ = note + .edit_content(rt) + .map_warn_err_str("Editing failed") + .map_err_trace_exit(1); + }) + .unwrap_or_else(|| { + error!("Cannot find note with name '{}'", name); + }); } fn list(rt: &Runtime) { use std::cmp::Ordering; - Note::all_notes(rt.store()) + rt.store() + .all_notes() .map_err_trace_exit(1) .map(|iter| { - let notes = iter.filter_map(|note| note.map_err_trace().ok()) + let notes = iter + .filter_map(|noteid| rt.store().get(noteid).map_err_trace_exit(1).unwrap()) .sorted_by(|note_a, note_b| { if let (Ok(a), Ok(b)) = (note_a.get_name(), note_b.get_name()) { return a.cmp(&b) From cefe58ffd48142128da1bcbe064176e5fe26ac3f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 14 Sep 2017 20:07:04 +0200 Subject: [PATCH 3/4] Add changelog --- doc/src/09020-changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/src/09020-changelog.md b/doc/src/09020-changelog.md index 6776d661..2a8085e3 100644 --- a/doc/src/09020-changelog.md +++ b/doc/src/09020-changelog.md @@ -58,6 +58,8 @@ This section contains the changelog from the last release to the next release. * The "toml-query" dependency was updated to 0.3.1 * `imag-timetrack track` is now able to parse "now", date-only start/stop dates and date-time start/stop times. + * `libimagnotes` does not longer wrap store types but extend them. + * Stats ## 0.3.0 From 5271255ae3254b94286cb881965962bac34966c0 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 15 Sep 2017 12:52:03 +0200 Subject: [PATCH 4/4] Fix libimagentryannotation for changes in libimagnotes --- .../src/annotation_fetcher.rs | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/entry/libimagentryannotation/src/annotation_fetcher.rs b/lib/entry/libimagentryannotation/src/annotation_fetcher.rs index 49890550..afdec887 100644 --- a/lib/entry/libimagentryannotation/src/annotation_fetcher.rs +++ b/lib/entry/libimagentryannotation/src/annotation_fetcher.rs @@ -20,8 +20,8 @@ use libimagstore::store::Entry; use libimagstore::store::Store; use libimagentrylink::internal::InternalLinker; -use libimagnotes::note::Note; -use libimagnotes::note::NoteIterator; +use libimagnotes::notestore::NoteStore; +use libimagnotes::iter::NoteIterator; use libimagstore::storeid::StoreIdIterator; use error::Result; @@ -43,8 +43,8 @@ impl<'a> AnnotationFetcher<'a> for Store { /// Wrapper around `Note::all_notes()` of `libimagnotes` which filters out normal notes and /// leaves only annotations in the iterator. fn all_annotations(&'a self) -> Result> { - Note::all_notes(self) - .map(|iter| AnnotationIter::new(iter)) + NoteStore::all_notes(self) + .map(|iter| AnnotationIter::new(iter, self)) .chain_err(|| AEK::StoreReadError) } @@ -59,8 +59,8 @@ impl<'a> AnnotationFetcher<'a> for Store { entry.get_internal_links() .chain_err(|| AEK::StoreReadError) .map(|iter| StoreIdIterator::new(Box::new(iter.map(|e| e.get_store_id().clone())))) - .map(|iter| NoteIterator::new(self, iter)) - .map(|iter| AnnotationIter::new(iter)) + .map(NoteIterator::new) + .map(|i| AnnotationIter::new(i, self)) } } @@ -70,8 +70,9 @@ pub mod iter { use toml_query::read::TomlValueReadExt; - use libimagnotes::note::Note; - use libimagnotes::note::NoteIterator; + use libimagnotes::iter::NoteIterator; + use libimagstore::store::Store; + use libimagstore::store::FileLockEntry; use error::Result; use error::AnnotationErrorKind as AEK; @@ -79,23 +80,23 @@ pub mod iter { use error::ResultExt; #[derive(Debug)] - pub struct AnnotationIter<'a>(NoteIterator<'a>); + pub struct AnnotationIter<'a>(NoteIterator, &'a Store); impl<'a> AnnotationIter<'a> { - pub fn new(noteiter: NoteIterator<'a>) -> AnnotationIter<'a> { - AnnotationIter(noteiter) + pub fn new(noteiter: NoteIterator, store: &'a Store) -> AnnotationIter<'a> { + AnnotationIter(noteiter, store) } } impl<'a> Iterator for AnnotationIter<'a> { - type Item = Result>; + type Item = Result>; - fn next(&mut self) -> Option>> { + fn next(&mut self) -> Option { loop { - match self.0.next() { - Some(Ok(note)) => { + match self.0.next().map(|id| self.1.get(id)) { + Some(Ok(Some(note))) => { match note.get_header().read("annotation.is_annotation") { Ok(None) => continue, // not an annotation Ok(Some(&Value::Boolean(true))) => return Some(Ok(note)), @@ -103,8 +104,9 @@ pub mod iter { Err(e) => return Some(Err(e).chain_err(|| AEK::HeaderReadError)), } }, - Some(Err(e)) => return Some(Err(e).chain_err(|| AEK::StoreReadError)), - None => return None, // iterator consumed + Some(Ok(None)) => continue, + Some(Err(e)) => return Some(Err(e).chain_err(|| AEK::StoreReadError)), + None => return None, // iterator consumed } } }