diff --git a/lib/domain/libimagtodo/src/builder.rs b/lib/domain/libimagtodo/src/builder.rs new file mode 100644 index 00000000..45cc45a7 --- /dev/null +++ b/lib/domain/libimagtodo/src/builder.rs @@ -0,0 +1,130 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2019 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 chrono::NaiveDateTime; +use failure::Fallible as Result; +use failure::err_msg; +use toml_query::insert::TomlValueInsertExt; +use uuid::Uuid; + +use libimagstore::store::Store; +use libimagstore::store::FileLockEntry; +use libimagentryutil::isa::Is; +use libimagutil::date::datetime_to_string; + +use crate::priority::Priority; +use crate::status::Status; +use crate::entry::IsTodo; +use crate::entry::TodoHeader; +use crate::store::date_sanity_check; + + +pub struct TodoBuilder { + uuid: Option, + status: Option, + scheduled: Option, + hidden: Option, + due: Option, + prio: Option, + check_sanity: bool, +} + +impl TodoBuilder { + pub(crate) fn new() -> Self { + TodoBuilder { + uuid: None, + status: None, + scheduled: None, + hidden: None, + due: None, + prio: None, + check_sanity: true, + } + } + + pub fn build<'a>(self, store: &'a Store) -> Result> { + let uuid = self.uuid.ok_or_else(|| err_msg("Uuid missing"))?; + let status = self.status.ok_or_else(|| err_msg("Status missing"))?; + + if self.check_sanity { + trace!("Checking sanity before creating todo"); + if let Err(s) = date_sanity_check(self.scheduled.as_ref(), self.hidden.as_ref(), self.due.as_ref()) { + trace!("Not sane."); + return Err(format_err!("{}", s)) + } + } + + let uuid_s = format!("{}", uuid.to_hyphenated_ref()); // TODO: not how it is supposed to be + debug!("Created new UUID for todo = {}", uuid_s); + + let mut entry = crate::module_path::new_id(uuid_s).and_then(|id| store.create(id))?; + + let header = TodoHeader { + uuid, + status, + scheduled: self.scheduled.as_ref().map(datetime_to_string), + hidden: self.hidden.as_ref().map(datetime_to_string), + due: self.due.as_ref().map(datetime_to_string), + priority: self.prio + }; + + debug!("Created header for todo: {:?}", header); + + let _ = entry.get_header_mut().insert_serialized("todo", header)?; + let _ = entry.set_isflag::()?; + + Ok(entry) + } + + pub fn with_uuid(mut self, uuid: Option) -> Self { + self.uuid = uuid; + self + } + + pub fn with_status(mut self, status: Option) -> Self { + self.status = status; + self + } + + pub fn with_scheduled(mut self, scheduled: Option) -> Self { + self.scheduled = scheduled; + self + } + + pub fn with_hidden(mut self, hidden: Option) -> Self { + self.hidden = hidden; + self + } + + pub fn with_due(mut self, due: Option) -> Self { + self.due = due; + self + } + + pub fn with_prio(mut self, prio: Option) -> Self { + self.prio = prio; + self + } + + pub fn with_check_sanity(mut self, b: bool) -> Self { + self.check_sanity = b; + self + } + +} diff --git a/lib/domain/libimagtodo/src/lib.rs b/lib/domain/libimagtodo/src/lib.rs index 8901077d..40cf5a87 100644 --- a/lib/domain/libimagtodo/src/lib.rs +++ b/lib/domain/libimagtodo/src/lib.rs @@ -34,6 +34,7 @@ extern crate libimagutil; #[macro_use] extern crate libimagstore; #[macro_use] extern crate libimagentryutil; +pub mod builder; pub mod entry; pub mod iter; pub mod priority; diff --git a/lib/domain/libimagtodo/src/store.rs b/lib/domain/libimagtodo/src/store.rs index cc1f2aa0..0aec566d 100644 --- a/lib/domain/libimagtodo/src/store.rs +++ b/lib/domain/libimagtodo/src/store.rs @@ -22,20 +22,19 @@ use std::result::Result as RResult; use failure::Fallible as Result; use chrono::NaiveDateTime; use uuid::Uuid; -use toml_query::insert::TomlValueInsertExt; use libimagstore::store::FileLockEntry; use libimagstore::store::Store; use libimagstore::iter::Entries; -use libimagutil::date::datetime_to_string; -use libimagentryutil::isa::Is; use crate::status::Status; use crate::priority::Priority; -use crate::entry::TodoHeader; -use crate::entry::IsTodo; +use crate::builder::TodoBuilder; pub trait TodoStore<'a> { + + fn todo_builder(&self) -> TodoBuilder; + fn create_todo(&'a self, status: Status, scheduled: Option, @@ -51,6 +50,13 @@ pub trait TodoStore<'a> { impl<'a> TodoStore<'a> for Store { + /// Get a TodoBuilder instance, which can be used to build a todo object. + /// + /// The TodoBuilder::new() constructor is not exposed, this function should be used instead. + fn todo_builder(&self) -> TodoBuilder { + TodoBuilder::new() + } + /// Create a new todo entry /// /// # Warning @@ -70,35 +76,15 @@ impl<'a> TodoStore<'a> for Store { prio: Option, check_sanity: bool) -> Result> { - if check_sanity { - trace!("Checking sanity before creating todo"); - if let Err(s) = date_sanity_check(scheduled.as_ref(), hidden.as_ref(), due.as_ref()) { - trace!("Not sane."); - return Err(format_err!("{}", s)) - } - } - - let uuid = Uuid::new_v4(); - let uuid_s = format!("{}", uuid.to_hyphenated_ref()); // TODO: not how it is supposed to be - debug!("Created new UUID for todo = {}", uuid_s); - - let mut entry = crate::module_path::new_id(uuid_s).and_then(|id| self.create(id))?; - - let header = TodoHeader { - uuid, - status, - scheduled: scheduled.as_ref().map(datetime_to_string), - hidden: hidden.as_ref().map(datetime_to_string), - due: due.as_ref().map(datetime_to_string), - priority: prio - }; - - debug!("Created header for todo: {:?}", header); - - let _ = entry.get_header_mut().insert_serialized("todo", header)?; - let _ = entry.set_isflag::()?; - - Ok(entry) + TodoBuilder::new() + .with_status(Some(status)) + .with_uuid(Some(Uuid::new_v4())) + .with_scheduled(scheduled) + .with_hidden(hidden) + .with_due(due) + .with_prio(prio) + .with_check_sanity(check_sanity) + .build(&self) } fn get_todo_by_uuid(&'a self, uuid: &Uuid) -> Result>> {