diff --git a/src/document/clock.rs b/src/document/clock.rs index 0ef01fe..373f216 100644 --- a/src/document/clock.rs +++ b/src/document/clock.rs @@ -1,5 +1,5 @@ use crate::{ - message::{Message, MsgAction, Records}, + message::wrapper::{Message, MsgAction, Records}, name::{Name, NameType, Names}, queue::{ data_director::{RegMsg, Register}, diff --git a/src/document/create.rs b/src/document/create.rs index 2d4a65e..5738158 100644 --- a/src/document/create.rs +++ b/src/document/create.rs @@ -3,7 +3,7 @@ use crate::{ definition::{DocDef, DocFuncType}, field::Field, }, - message::{ + message::wrapper::{ Action, CalcValue, Calculation, InternalRecord, InternalRecords, Message, MsgAction, Oid, Query, Records, Reply, Update, }, @@ -317,7 +317,7 @@ impl Indexes { #[cfg(test)] mod indexes { use super::*; - use crate::{document::field::FieldType, message::Operand}; + use crate::{document::field::FieldType, message::wrapper::Operand}; fn get_fields(count: usize) -> Vec { let mut output = Vec::new(); @@ -814,7 +814,7 @@ mod document_files { use super::*; use crate::{ document::field::FieldType, - message::{Addition, Delete, Operand}, + message::wrapper::{Addition, Delete, Operand}, name::{Name, Names}, support_tests::TIMEOUT, }; diff --git a/src/document/definition.rs b/src/document/definition.rs index 8ee8321..c55b2ec 100644 --- a/src/document/definition.rs +++ b/src/document/definition.rs @@ -3,7 +3,7 @@ use crate::{ create::IndexType, field::{Field, FieldType}, }, - message::{Action, CalcValue, MsgAction}, + message::wrapper::{Action, CalcValue, MsgAction}, mtterror::MTTError, name::{Name, NameType, Names}, queue::data_director::{Include, Path}, @@ -75,7 +75,7 @@ impl FieldSetting { #[cfg(test)] mod fieldsettings { use super::*; - use crate::message::{Calculation, Operand}; + use crate::message::wrapper::{Calculation, Operand}; use chrono::Utc; use std::time::Duration; @@ -379,7 +379,7 @@ impl DocDef { #[cfg(test)] mod docdefs { use super::*; - use crate::message::{Query, Update}; + use crate::message::wrapper::{Query, Update}; #[test] fn can_field_be_added() { diff --git a/src/document/session.rs b/src/document/session.rs index 504b3dd..f2ab8ac 100644 --- a/src/document/session.rs +++ b/src/document/session.rs @@ -4,7 +4,7 @@ use crate::{ definition::{DocDef, DocFuncType}, field::FieldType, }, - message::{Action, CalcValue, Calculation, Delete, Message, Operand, Query, Update}, + message::wrapper::{Action, CalcValue, Calculation, Delete, Message, Operand, Query, Update}, name::{Name, NameType}, queue::{ data_director::{Include, Path, RegMsg, Register}, @@ -89,7 +89,7 @@ mod sessions { use super::*; use crate::{ document::{clock::Clock, create::CreateDoc, field::Field}, - message::{Addition, MsgAction, Query, Records}, + message::wrapper::{Addition, MsgAction, Query, Records}, mtterror::MTTError, name::{Name, NameType, Names}, queue::data_director::{Include, Path, RegMsg, Register}, diff --git a/src/lib.rs b/src/lib.rs index c2ec4fe..0e742b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,8 +10,8 @@ use document::{ field::{Field, FieldType}, session::Session, }; -use message::{Action, Addition, CalcValue, Calculation, Message, Operand}; -pub use message::{MsgAction, Query}; +use message::wrapper::{Action, Addition, CalcValue, Calculation, Message, Operand}; +pub use message::wrapper::{MsgAction, Query}; use name::{Name, NameType}; use queue::{ data_director::{Include, Path, RegMsg, Register}, diff --git a/src/message.rs b/src/message.rs index ba2f942..e4ea5ca 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,1688 +1 @@ -use crate::{ - document::{ - definition::DocDef, - field::{Field, FieldType}, - }, - mtterror::MTTError, - name::{NameType, Names}, - queue::data_director::{Include, Path, Register, Route}, -}; -use chrono::prelude::*; -use std::{ - collections::{HashMap, HashSet}, - time::Duration, -}; -use uuid::Uuid; - -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub enum Action { - Addition, - Create, - Delete, - Error, - GetLog, - Log, - OnAddition, - OnDelete, - OnQuery, - OnUpdate, - Query, - Records, - Register, - Reply, - Show, - Update, -} - -impl From for Action { - fn from(value: MsgAction) -> Self { - match value { - MsgAction::Addition(_) => Action::Addition, - MsgAction::Create(_) => Action::Create, - MsgAction::Delete(_) => Action::Delete, - MsgAction::Error(_) => Action::Error, - MsgAction::GetLog(_) => Action::GetLog, - MsgAction::OnAddition(_) => Action::OnAddition, - MsgAction::OnDelete(_) => Action::OnDelete, - MsgAction::OnQuery(_) => Action::OnQuery, - MsgAction::OnUpdate(_) => Action::OnUpdate, - MsgAction::Query(_) => Action::Query, - MsgAction::Records(_) => Action::Records, - MsgAction::Register(_) => Action::Register, - MsgAction::Reply(_) => Action::Reply, - MsgAction::Show => Action::Show, - MsgAction::Update(_) => Action::Update, - } - } -} - -impl From<&MsgAction> for Action { - fn from(value: &MsgAction) -> Self { - let action = value.clone(); - Self::from(action) - } -} - -#[derive(Clone, Debug)] -pub enum MsgAction { - Addition(Addition), - Create(DocDef), - // Alter - // Remove - Error(MTTError), - GetLog(Uuid), - OnAddition(Records), - OnDelete(Records), - OnQuery(Records), - OnUpdate(Records), - Query(Query), - Records(Records), - Register(Register), - Reply(Reply), - Show, - Delete(Delete), - Update(Update), -} - -impl From for MsgAction { - fn from(value: Addition) -> Self { - MsgAction::Addition(value) - } -} - -impl From for MsgAction { - fn from(value: Delete) -> Self { - MsgAction::Delete(value) - } -} - -impl From for MsgAction { - fn from(value: DocDef) -> Self { - MsgAction::Create(value) - } -} - -impl From for MsgAction { - fn from(value: MTTError) -> Self { - MsgAction::Error(value) - } -} - -impl From for MsgAction { - fn from(value: Query) -> Self { - MsgAction::Query(value) - } -} - -impl From for MsgAction { - fn from(value: Records) -> Self { - MsgAction::Records(value) - } -} - -impl From for MsgAction { - fn from(value: Register) -> Self { - MsgAction::Register(value) - } -} - -impl From for MsgAction { - fn from(value: Reply) -> Self { - MsgAction::Reply(value) - } -} - -impl From for MsgAction { - fn from(value: Update) -> Self { - MsgAction::Update(value) - } -} - -impl From for MsgAction { - fn from(value: Uuid) -> Self { - MsgAction::GetLog(value) - } -} - -impl From<&Uuid> for MsgAction { - fn from(value: &Uuid) -> Self { - Self::from(value.clone()) - } -} - -#[cfg(test)] -mod msgactions { - use super::*; - use crate::name::Name; - - #[test] - fn turn_document_definition_into_action() { - let name = Name::english(Uuid::new_v4().to_string().as_str()); - let value = DocDef::new(name.clone()); - let result: MsgAction = value.into(); - match result { - MsgAction::Create(def) => assert_eq!(def.get_document_names(), &[name].to_vec()), - _ => unreachable!("Got {:?}: dhould have been create", result), - } - } - - #[test] - fn turn_error_into_action() { - let data = "data".to_string(); - let value = MTTError::DocumentAlreadyExists(data.clone()); - let result: MsgAction = value.into(); - match result { - MsgAction::Error(result) => match result { - MTTError::DocumentAlreadyExists(output) => assert_eq!(output, data), - _ => unreachable!("Got {:?}: dhould have been create", result), - }, - _ => unreachable!("Got {:?}: dhould have been create", result), - } - let value = MTTError::DocumentNotFound(data.clone()); - let result: MsgAction = value.into(); - match result { - MsgAction::Error(result) => match result { - MTTError::DocumentNotFound(output) => assert_eq!(output, data), - _ => unreachable!("Got {:?}: dhould have been create", result), - }, - _ => unreachable!("Got {:?}: dhould have been create", result), - } - } - - #[test] - fn turn_query_into_action() { - let value = Query::new(); - let result: MsgAction = value.into(); - match result { - MsgAction::Query(_) => {} - _ => unreachable!("Got {:?}: dhould have been query", result), - } - } - - #[test] - fn turn_reply_into_action() { - let value = Reply::new(); - let result: MsgAction = value.into(); - match result { - MsgAction::Reply(_) => {} - _ => unreachable!("Got {:?}: dhould have been reply", result), - } - } -} - -#[derive(Clone, Debug)] -pub struct Message { - msg_id: Uuid, - document_id: NameType, - action: MsgAction, - route: Route, - // session: Option -} - -impl Message { - pub fn new(doc_id: D, action: A) -> Self - where - D: Into, - A: Into, - { - Self { - msg_id: Uuid::new_v4(), - document_id: doc_id.into(), - action: action.into(), - route: Route::default(), - } - } - - pub fn get_message_id(&self) -> &Uuid { - &self.msg_id - } - - pub fn get_action(&self) -> &MsgAction { - &self.action - } - - pub fn get_path(&self) -> Path { - Path::new( - Include::Just(self.msg_id.clone()), - Include::Just(self.document_id.clone()), - Include::Just(self.action.clone().into()), - ) - } - - pub fn get_route(&self) -> Route { - self.route.clone() - } - - pub fn set_route(&mut self, route: Route) { - self.route = route; - } - - pub fn response(&self, action: A) -> Self - where - A: Into, - { - Self { - msg_id: self.msg_id.clone(), - document_id: self.document_id.clone(), - action: action.into(), - route: Route::default(), - } - } - - pub fn forward(&self, doc_id: D, action: A) -> Self - where - D: Into, - A: Into, - { - Self { - msg_id: self.msg_id.clone(), - document_id: doc_id.into(), - action: action.into(), - route: Route::default(), - } - } -} - -#[cfg(test)] -mod messages { - use super::*; - use crate::name::Name; - - #[test] - fn can_the_document_be_a_named_reference() { - let dts = [Name::english("one"), Name::english("two")]; - for document in dts.into_iter() { - let msg = Message::new( - document.clone(), - MsgAction::Create(DocDef::new(document.clone())), - ); - match &msg.document_id { - NameType::Name(data) => assert_eq!(data, &document), - _ => unreachable!("should have been a string id"), - } - match msg.get_action() { - MsgAction::Create(_) => {} - _ => unreachable!("should have been a create document"), - } - } - } - - #[test] - fn can_the_document_be_an_id() { - let document = Uuid::new_v4(); - let msg = Message::new(document.clone(), Query::new()); - match msg.document_id { - NameType::ID(data) => assert_eq!(data, document), - _ => unreachable!("should have been an id"), - } - match msg.get_action() { - MsgAction::Query(_) => {} - _ => unreachable!("should have been an access query"), - } - } - - #[test] - fn do_messages_contain_routes() { - let mut msg = Message::new(Name::english("whatever"), Query::new()); - let default_route = msg.get_route(); - match default_route.msg_id { - Include::Just(_) => unreachable!("should defalt to all"), - Include::All => {} - } - match default_route.doc_id { - Include::Just(_) => unreachable!("should defalt to all"), - Include::All => {} - } - match default_route.action { - Include::Just(_) => unreachable!("should defalt to all"), - Include::All => {} - } - let doc_id = Uuid::new_v4(); - let route = Route::new( - Include::Just(msg.get_message_id().clone()), - Include::Just(doc_id.clone()), - Include::Just(msg.get_action().into()), - ); - msg.set_route(route); - let result = msg.get_route(); - match result.msg_id { - Include::Just(data) => assert_eq!(&data, msg.get_message_id()), - Include::All => unreachable!("should have message id"), - } - match result.doc_id { - Include::Just(data) => assert_eq!(data, doc_id), - Include::All => unreachable!("should have document id"), - } - match result.action { - Include::Just(data) => assert_eq!(data, msg.get_action().into()), - Include::All => unreachable!("should have action"), - } - } - - #[test] - fn is_the_message_id_random() { - let mut ids: Vec = Vec::new(); - for _ in 0..5 { - let msg = Message::new(Name::english("tester"), Query::new()); - let id = msg.get_message_id().clone(); - assert!(!ids.contains(&id), "{:?} containts {}", ids, id); - ids.push(id); - } - } - - #[test] - fn can_make_reply_message() { - let name = Name::english("testing"); - let msg = Message::new(name.clone(), Query::new()); - let responce = Reply::new(); - let reply = msg.response(responce); - assert_eq!(reply.get_message_id(), msg.get_message_id()); - match &reply.document_id { - NameType::Name(data) => assert_eq!(data, &name), - _ => unreachable!("should have been a name"), - } - match reply.get_action() { - MsgAction::Reply(_) => {} - _ => unreachable!("should have been a reply"), - } - } - - #[test] - fn can_make_error_message() { - let name = Name::english("testing"); - let msg = Message::new(name.clone(), Query::new()); - let err_msg = Uuid::new_v4().to_string(); - let result = msg.response(MTTError::DocumentNotFound(err_msg.clone())); - assert_eq!(result.get_message_id(), msg.get_message_id()); - match &result.document_id { - NameType::Name(data) => assert_eq!(data, &name), - _ => unreachable!("should have been a name"), - } - match result.get_action() { - MsgAction::Error(data) => match data { - MTTError::DocumentNotFound(txt) => assert_eq!(txt, &err_msg), - _ => unreachable!("got {:?}, should have received not found", data), - }, - _ => unreachable!("should have been a reply"), - } - } - - #[test] - fn can_make_a_response_message() { - let doc_id = Uuid::new_v4(); - let msg = Message::new(doc_id.clone(), Query::new()); - let data = Uuid::new_v4().to_string(); - let result1 = msg.response(MTTError::DocumentNotFound(data.clone())); - let result2 = msg.response(Reply::new()); - assert_eq!(result1.get_message_id(), msg.get_message_id()); - assert_eq!(result2.get_message_id(), msg.get_message_id()); - assert_eq!(result1.document_id, msg.document_id); - assert_eq!(result2.document_id, msg.document_id); - let action1 = result1.get_action(); - match action1 { - MsgAction::Error(err) => match err { - MTTError::DocumentNotFound(output) => assert_eq!(output, &data), - _ => unreachable!("got {:?}: should have received document not found", err), - }, - _ => unreachable!("got {:?}: should have received error", action1), - } - let action2 = result2.get_action(); - match action2 { - MsgAction::Reply(data) => assert_eq!(data.len(), 0), - _ => unreachable!("got {:?}: should have received a reply", action2), - } - } -} - -#[derive(Clone, Debug)] -pub struct Addition { - data: Document, -} - -impl Addition { - pub fn new() -> Self { - Self { - data: Document::new(), - } - } - - #[allow(dead_code)] - pub fn add_field(&mut self, name: NT, field: CV) - where - CV: Into, - NT: Into, - { - self.data.add_field(name, field); - } - - #[allow(dead_code)] - fn get_field(&self, name: NT) -> &CalcValue - where - NT: Into, - { - self.data.get_field(name) - } - - #[allow(dead_code)] - fn get_document(&self) -> Document { - self.data.clone() - } - - pub fn iter(&self) -> impl Iterator { - self.data.iter() - } -} - -#[cfg(test)] -mod additions { - use super::*; - use crate::name::Name; - - #[test] - fn can_add_static_string() { - let mut add = Addition::new(); - let name = Name::english(Uuid::new_v4().to_string().as_str()); - let data = Uuid::new_v4().to_string(); - add.add_field(name.clone(), data.clone()); - let result = add.get_field(&name); - match result { - CalcValue::Value(result) => match result { - Field::StaticString(output) => assert_eq!(output, &data), - _ => unreachable!("got {:?}, should have been a string", result), - }, - _ => unreachable!("got {:?}: should have received value", result), - } - } - - #[test] - fn can_add_uuid() { - let mut add = Addition::new(); - let name = Name::english(Uuid::new_v4().to_string().as_str()); - let data = Uuid::new_v4(); - add.add_field(name.clone(), data.clone()); - let output = add.get_field(&name); - match output { - CalcValue::Value(result) => match result { - Field::Uuid(result) => assert_eq!(result, &data), - _ => unreachable!("got {:?}: should have received uuid", result), - }, - _ => unreachable!("got {:?}: should have received value", output), - } - } - - #[test] - fn can_get_document() { - let mut add = Addition::new(); - let name = Name::english(Uuid::new_v4().to_string().as_str()); - let data = Uuid::new_v4(); - add.add_field(name.clone(), data.clone()); - let doc = add.get_document(); - let output = doc.get_field(&name); - match output { - CalcValue::Value(holder) => match holder { - Field::Uuid(result) => assert_eq!(result, &data), - _ => unreachable!("should have received uuid"), - }, - _ => unreachable!("got {:?}: should have received value", output), - } - } -} - -#[derive(Clone, Debug)] -pub enum Operand { - Add, - Equal, - GreaterThan, - GreaterThanEqual, - LessThan, - LessThanEqual, -} - -impl Operand { - #[allow(dead_code)] - fn validate(&self, x: &Field, y: &Field) -> bool { - match self { - Self::Equal => x == y, - Self::GreaterThan => x > y, - Self::GreaterThanEqual => x >= y, - Self::LessThan => x < y, - Self::LessThanEqual => x <= y, - _ => false, - } - } -} - -#[cfg(test)] -mod operands { - use super::*; - - #[test] - fn equals_true() { - let data: Field = Uuid::new_v4().into(); - assert!(Operand::Equal.validate(&data, &data)); - } - - #[test] - fn equals_false() { - let x: Field = Uuid::new_v4().into(); - let mut y: Field = Uuid::new_v4().into(); - while x == y { - y = Uuid::new_v4().into(); - } - assert!(!Operand::Equal.validate(&x, &y)); - } - - #[test] - fn does_greater() { - let data: Vec = vec![1.into(), 2.into(), 3.into()]; - assert!(!Operand::GreaterThan.validate(&data[0], &data[1])); - assert!(!Operand::GreaterThan.validate(&data[1], &data[1])); - assert!(Operand::GreaterThan.validate(&data[2], &data[1])); - } - - #[test] - fn does_greater_equal() { - let data: Vec = vec![1.into(), 2.into(), 3.into()]; - assert!(!Operand::GreaterThanEqual.validate(&data[0], &data[1])); - assert!(Operand::GreaterThanEqual.validate(&data[1], &data[1])); - assert!(Operand::GreaterThanEqual.validate(&data[2], &data[1])); - } - - #[test] - fn does_lesser() { - let data: Vec = vec![1.into(), 2.into(), 3.into()]; - assert!(Operand::LessThan.validate(&data[0], &data[1])); - assert!(!Operand::LessThan.validate(&data[1], &data[1])); - assert!(!Operand::LessThan.validate(&data[2], &data[1])); - } - - #[test] - fn does_lesser_equal() { - let data: Vec = vec![1.into(), 2.into(), 3.into()]; - assert!(Operand::LessThanEqual.validate(&data[0], &data[1])); - assert!(Operand::LessThanEqual.validate(&data[1], &data[1])); - assert!(!Operand::LessThanEqual.validate(&data[2], &data[1])); - } -} - -#[derive(Clone, Debug)] -pub enum CalcValue { - Calculate(Calculation), - Existing(FieldType), - FType(FieldType), - None, - Value(Field), -} - -impl CalcValue { - pub fn get(&self, existing: &Field) -> Field { - match self { - Self::Calculate(calc) => calc.calculate(existing), - Self::Existing(_) => existing.clone(), - Self::FType(ftype) => ftype.get_default(), - Self::None => Field::None, - Self::Value(field) => field.clone(), - } - } - - fn get_type(&self) -> FieldType { - match self { - Self::Calculate(calc) => calc.get_type(), - Self::Existing(ftype) => ftype.clone(), - Self::FType(ftype) => ftype.clone(), - Self::None => FieldType::None, - Self::Value(field) => field.into(), - } - } -} - -impl From for CalcValue { - fn from(value: Calculation) -> Self { - Self::Calculate(value) - } -} - -impl From for CalcValue { - fn from(value: Field) -> Self { - Self::Value(value) - } -} - -impl From<&Field> for CalcValue { - fn from(value: &Field) -> Self { - Self::from(value.clone()) - } -} - -impl From for CalcValue { - fn from(value: FieldType) -> Self { - Self::FType(value) - } -} - -impl From for CalcValue { - fn from(value: bool) -> Self { - let output: Field = value.into(); - Self::from(output).into() - } -} - -impl From> for CalcValue { - fn from(value: DateTime) -> Self { - let output: Field = value.into(); - Self::from(output).into() - } -} - -impl From for CalcValue { - fn from(value: Duration) -> Self { - let output: Field = value.into(); - Self::from(output).into() - } -} - -impl From for CalcValue { - fn from(value: i128) -> Self { - let output: Field = value.into(); - Self::from(output).into() - } -} - -impl From<&str> for CalcValue { - fn from(value: &str) -> Self { - let output: Field = value.into(); - Self::from(output).into() - } -} - -impl From for CalcValue { - fn from(value: String) -> Self { - let output: Field = value.into(); - Self::from(output).into() - } -} - -impl From for CalcValue { - fn from(value: Uuid) -> Self { - let output: Field = value.into(); - Self::from(output).into() - } -} - -#[cfg(test)] -mod calcvalues { - use super::*; - - #[test] - fn from_uuid() { - let value = Uuid::new_v4(); - let expected: Field = value.into(); - let result: CalcValue = value.into(); - match result.clone() { - CalcValue::Value(data) => assert_eq!(data, expected), - _ => unreachable!("got {:?}, should have gotten a field", result), - } - assert_eq!(result.get(&Field::None), expected); - } - - #[test] - fn from_str() { - let value = "something"; - let expected: Field = value.into(); - let result: CalcValue = value.into(); - match result.clone() { - CalcValue::Value(data) => assert_eq!(data, expected), - _ => unreachable!("got {:?}, should have gotten a field", result), - } - assert_eq!(result.get(&Field::None), expected); - } - - #[test] - fn from_string() { - let value = "data".to_string(); - let expected: Field = value.clone().into(); - let result: CalcValue = value.into(); - match result.clone() { - CalcValue::Value(data) => assert_eq!(data, expected), - _ => unreachable!("got {:?}, should have gotten a field", result), - } - assert_eq!(result.get(&Field::None), expected); - } - - #[test] - fn from_boolean() { - let value = true; - let expected: Field = value.clone().into(); - let result: CalcValue = value.into(); - match result.clone() { - CalcValue::Value(data) => assert_eq!(data, expected), - _ => unreachable!("got {:?}, should have gotten a field", result), - } - assert_eq!(result.get(&Field::None), expected); - } - - #[test] - fn from_datetime() { - let value = Utc::now(); - let expected: Field = value.clone().into(); - let result: CalcValue = value.into(); - match result.clone() { - CalcValue::Value(data) => assert_eq!(data, expected), - _ => unreachable!("got {:?}, should have gotten a field", result), - } - assert_eq!(result.get(&Field::None), expected); - } - - #[test] - fn from_duration() { - let value = Duration::from_secs(5); - let expected: Field = value.clone().into(); - let result: CalcValue = value.into(); - match result.clone() { - CalcValue::Value(data) => assert_eq!(data, expected), - _ => unreachable!("got {:?}, should have gotten a field", result), - } - assert_eq!(result.get(&Field::None), expected); - } - - #[test] - fn from_integer() { - let value: i128 = 5; - let expected: Field = value.clone().into(); - let result: CalcValue = value.into(); - match result.clone() { - CalcValue::Value(data) => assert_eq!(data, expected), - _ => unreachable!("got {:?}, should have gotten a field", result), - } - assert_eq!(result.get(&Field::None), expected); - } - - #[test] - fn from_calculation() { - let duration = Duration::from_secs(300); - let start = Utc::now() + duration; - let mut calc = Calculation::new(Operand::Add); - calc.add_value(FieldType::DateTime).unwrap(); - calc.add_value(duration.clone()).unwrap(); - let result: CalcValue = calc.into(); - let data = match result.get(&Field::None) { - Field::DateTime(data) => data, - _ => unreachable!(), - }; - let stop = Utc::now() + duration; - assert!( - data > start && data < stop, - "should be about 5 minutes ahead" - ); - } -} - -#[derive(Clone, Debug)] -pub struct Calculation { - operation: Operand, - values: Vec, -} - -impl Calculation { - pub fn new(operand: Operand) -> Self { - Self { - operation: operand, - values: Vec::new(), - } - } - - #[allow(dead_code)] - fn operation(&self) -> &Operand { - &self.operation - } - - #[allow(dead_code)] - fn get_fields(&self, existing: Field) -> Vec { - let mut output = Vec::new(); - for item in self.values.iter() { - output.push(item.get(&existing)); - } - output - } - - pub fn get_type(&self) -> FieldType { - if self.values.is_empty() { - FieldType::None - } else { - self.values[0].get_type() - } - } - - pub fn add_value(&mut self, data: CV) -> Result<(), MTTError> - where - CV: Into, - { - let holder: CalcValue = data.into(); - if self.values.is_empty() { - self.values.push(holder); - return Ok(()); - } - let mut base = self.get_type(); - match self.operation { - Operand::Add => match base { - FieldType::DateTime => base = FieldType::Duration, - _ => {} - }, - _ => {} - } - let ftype = holder.get_type(); - if base == ftype { - self.values.push(holder); - } else { - return Err(MTTError::DocumentFieldWrongDataType(base, ftype)); - } - Ok(()) - } - - #[allow(dead_code)] - fn validate_value(&self, value: CV) -> Result<(), MTTError> - where - CV: Into, - { - if self.values.is_empty() { - return Ok(()); - } - let holder = value.into(); - let mut base = self.get_type(); - match self.operation { - Operand::Add => { - if base == FieldType::DateTime { - base = FieldType::Duration; - } - } - _ => {} - } - let ftype = holder.get_type(); - if base == ftype { - Ok(()) - } else { - Err(MTTError::DocumentFieldWrongDataType(base, ftype)) - } - } - - pub fn calculate(&self, existing: &Field) -> Field { - let mut result = Field::None; - match self.operation { - Operand::Add => { - let mut first = true; - for value in self.values.iter() { - let data = value.get(existing); - if first { - result = data; - first = false; - } else { - result += data; - } - } - } - Operand::Equal => { - if self.values.len() >= 2 { - result = self.values[0] - .get(existing) - .equal(&self.values[1].get(existing)); - } - } - Operand::GreaterThan => { - if self.values.len() >= 2 { - result = self.values[0] - .get(existing) - .greater(&self.values[1].get(existing)); - } - } - Operand::GreaterThanEqual => { - if self.values.len() >= 2 { - result = self.values[0] - .get(existing) - .greater_equal(&self.values[1].get(existing)); - } - } - Operand::LessThan => { - if self.values.len() >= 2 { - result = self.values[0] - .get(existing) - .lesser(&self.values[1].get(existing)); - } - } - Operand::LessThanEqual => { - if self.values.len() >= 2 { - result = self.values[0] - .get(existing) - .lesser_equal(&self.values[1].get(existing)); - } - } - } - result - } -} - -#[cfg(test)] -mod calculations { - use super::*; - use rand::random; - - #[test] - fn errors_on_different_field_types() { - let mut calc = Calculation::new(Operand::Equal); - calc.add_value(Uuid::nil()).unwrap(); - match calc.add_value("other") { - Ok(_) => unreachable!("should have errored with wrong type"), - Err(err) => match err { - MTTError::DocumentFieldWrongDataType(expected, got) => { - assert_eq!(expected, FieldType::Uuid); - assert_eq!(got, FieldType::StaticString); - } - _ => unreachable!("got {:?}, expected wrong field type", err), - }, - } - } - - #[test] - fn returns_reference_to_operand() { - let calc = Calculation::new(Operand::Add); - match calc.operation() { - Operand::Add => {} - _ => unreachable!("got {:?}, shold have gotten assign", calc.operation()), - } - let calc = Calculation::new(Operand::Equal); - match calc.operation() { - Operand::Equal => {} - _ => unreachable!("got {:?}, shold have gotten assign", calc.operation()), - } - } - - #[test] - fn can_equal_true() { - let mut calc = Calculation::new(Operand::Equal); - let data: Field = Uuid::new_v4().into(); - calc.add_value(data.clone()).unwrap(); - calc.add_value(data.clone()).unwrap(); - let expected: Field = true.into(); - let result = calc.calculate(&Field::None); - assert_eq!(result, expected); - } - - #[test] - fn can_equal_false() { - let mut calc = Calculation::new(Operand::Equal); - let value1: Field = "fred".into(); - let value2: Field = "barney".into(); - calc.add_value(value1).unwrap(); - calc.add_value(value2).unwrap(); - let expected: Field = false.into(); - let result = calc.calculate(&Field::None); - assert_eq!(result, expected); - } - - #[test] - fn can_greater_than() { - let data: Vec<(Field, Field)> = vec![ - (0.into(), false.into()), - (1.into(), false.into()), - (2.into(), true.into()), - ]; - for (item, expected) in data.iter() { - let mut calc = Calculation::new(Operand::GreaterThan); - calc.add_value(item.clone()).unwrap(); - calc.add_value(data[1].0.clone()).unwrap(); - let result = calc.calculate(&Field::None); - assert_eq!(&result, expected); - } - } - - #[test] - fn can_greater_than_equal() { - let data: Vec<(Field, Field)> = vec![ - (0.into(), false.into()), - (1.into(), true.into()), - (2.into(), true.into()), - ]; - for (item, expected) in data.iter() { - let mut calc = Calculation::new(Operand::GreaterThanEqual); - calc.add_value(item.clone()).unwrap(); - calc.add_value(data[1].0.clone()).unwrap(); - let result = calc.calculate(&Field::None); - assert_eq!(&result, expected); - } - } - - #[test] - fn can_lesser_than() { - let data: Vec<(Field, Field)> = vec![ - (0.into(), true.into()), - (1.into(), false.into()), - (2.into(), false.into()), - ]; - for (item, expected) in data.iter() { - let mut calc = Calculation::new(Operand::LessThan); - calc.add_value(item.clone()).unwrap(); - calc.add_value(data[1].0.clone()).unwrap(); - let result = calc.calculate(&Field::None); - assert_eq!(&result, expected); - } - } - - #[test] - fn can_lesser_than_equal() { - let data: Vec<(Field, Field)> = vec![ - (0.into(), true.into()), - (1.into(), true.into()), - (2.into(), false.into()), - ]; - for (item, expected) in data.iter() { - let mut calc = Calculation::new(Operand::LessThanEqual); - calc.add_value(item.clone()).unwrap(); - calc.add_value(data[1].0.clone()).unwrap(); - let result = calc.calculate(&Field::None); - assert_eq!(&result, expected); - } - } - - #[test] - fn can_add_numbers() { - let mut calc = Calculation::new(Operand::Add); - let value1: i128 = random::().into(); - let value2: i128 = random::().into(); - let expected: Field = { value1 + value2 }.into(); - let value1: Field = value1.into(); - let value2: Field = value2.into(); - calc.add_value(value1.clone()).unwrap(); - calc.add_value(value2.clone()).unwrap(); - let result = calc.calculate(&Field::None); - assert_eq!( - result, expected, - "{:?} plus {:?} should equal {:?}", - value1, value2, expected - ); - } - - #[test] - fn can_use_existing_values() { - let mut calc = Calculation::new(Operand::Add); - let value1: i128 = random::().into(); - let value2: i128 = random::().into(); - let expected: Field = { value1 + value2 }.into(); - let value1: Field = value1.into(); - let value2: Field = value2.into(); - calc.add_value(value1.clone()).unwrap(); - calc.add_value(CalcValue::Existing(FieldType::Integer)) - .unwrap(); - let result = calc.calculate(&value2); - assert_eq!( - result, expected, - "{:?} plus {:?} should equal {:?}", - value1, value2, expected - ); - } - - #[test] - fn returns_error_on_mismatch() { - let mut calc = Calculation::new(Operand::Add); - calc.add_value(Uuid::nil()).unwrap(); - match calc.add_value("mismatch") { - Ok(_) => unreachable!("should have returned an error"), - Err(err) => match err { - MTTError::DocumentFieldWrongDataType(expected, got) => { - assert_eq!(got, FieldType::StaticString); - assert_eq!(expected, FieldType::Uuid); - } - _ => unreachable!("got {:?}, expected wrong field type", err), - }, - } - } - - #[test] - fn datetime_accepts_duration() { - let mut calc = Calculation::new(Operand::Add); - let duration = Duration::from_secs(3600); - let start = Utc::now() + duration; - calc.add_value(FieldType::DateTime).unwrap(); - match calc.add_value(duration.clone()) { - Ok(_) => {} - Err(err) => unreachable!("got {:?}, should have returned normally", err), - } - let result = calc.calculate(&Field::None); - let stop = Utc::now() + duration; - match result { - Field::DateTime(data) => { - assert!(data > start); - assert!(data < stop); - } - _ => unreachable!("got {:?}, should have been datetime", result), - } - } -} - -#[allow(dead_code)] -#[derive(Clone, Debug)] -pub struct Operation { - field_name: String, - operation: Operand, - value: Field, -} - -#[allow(dead_code)] -impl Operation { - pub fn new(name: String, op: Operand, value: F) -> Self - where - F: Into, - { - Self { - field_name: name, - operation: op, - value: value.into(), - } - } - - fn which_field(&self) -> String { - self.field_name.clone() - } - - pub fn validate(&self, field: &Field) -> bool { - self.operation.validate(field, &self.value) - } -} - -#[allow(dead_code)] -#[derive(Clone, Debug)] -enum QueryType { - Query(Query), - Oids(HashSet), -} - -impl From for QueryType { - fn from(value: Query) -> Self { - QueryType::Query(value) - } -} - -impl From> for QueryType { - fn from(value: HashSet) -> Self { - QueryType::Oids(value) - } -} - -#[derive(Clone, Debug)] -pub struct Query { - data: HashMap, -} - -impl Query { - pub fn new() -> Self { - Self { - data: HashMap::new(), - } - } - - pub fn add(&mut self, name: NT, operation: Calculation) - where - NT: Into, - { - self.data.insert(name.into(), operation); - } - - #[allow(dead_code)] - fn get(&self, name: NT) -> Option - where - NT: Into, - { - match self.data.get(&name.into()) { - Some(calc) => Some(calc.clone()), - None => None, - } - } - - #[allow(dead_code)] - fn field_ids(&self) -> HashSet<&NameType> { - self.data.keys().collect() - } - - pub fn iter(&self) -> impl Iterator { - self.data.iter() - } -} - -#[cfg(test)] -mod queries { - use super::*; - use crate::name::Name; - - #[test] - fn holds_calculation_to_run_query() { - let name = Name::english(Uuid::new_v4().to_string().as_str()); - let data = Uuid::new_v4(); - let mut bad_data = data.clone(); - while bad_data == data { - bad_data = Uuid::new_v4(); - } - let mut query = Query::new(); - let mut calc = Calculation::new(Operand::Equal); - calc.add_value(data.clone()).unwrap(); - query.add(name.clone(), calc); - match query.get(&name) { - Some(op) => { - let expected: Field = true.into(); - let mut holder = op.clone(); - holder.add_value(data).unwrap(); - assert_eq!(holder.calculate(&Field::None), expected); - } - None => unreachable!("should have returned a calculation"), - } - match query.get(&name) { - Some(op) => { - let expected: Field = false.into(); - let mut holder = op.clone(); - holder.add_value(bad_data).unwrap(); - assert_eq!(holder.calculate(&Field::None), expected); - } - None => unreachable!("should have returned a calculation"), - } - } -} - -#[allow(dead_code)] -#[derive(Clone, Debug)] -pub struct Reply { - data: Vec, -} - -#[allow(dead_code)] -impl Reply { - pub fn new() -> Self { - Self { data: Vec::new() } - } - - fn add(&mut self, doc: Document) { - self.data.push(doc); - } - - pub fn len(&self) -> usize { - self.data.len() - } - - fn iter(&self) -> impl Iterator { - self.data.iter() - } -} - -#[cfg(test)] -mod replies { - use super::*; - use crate::name::Name; - - #[test] - fn is_new_empty() { - let reply = Reply::new(); - assert_eq!(reply.len(), 0, "should have no records"); - } - - #[test] - fn can_add_documents() { - let mut reply = Reply::new(); - let doc = Document::new(); - reply.add(doc.clone()); - assert_eq!(reply.len(), 1); - reply.add(doc.clone()); - assert_eq!(reply.len(), 2); - } - - #[test] - fn can_retrieve_documents() { - let fieldname = Name::english("field"); - let mut doc1 = Document::new(); - doc1.add_field(fieldname.clone(), "one"); - let mut doc2 = Document::new(); - doc2.add_field(fieldname.clone(), "two"); - let mut reply = Reply::new(); - reply.add(doc1); - reply.add(doc2); - let mut reply_iter = reply.iter(); - let result1 = reply_iter.next().unwrap(); - match result1.get_field(&fieldname) { - CalcValue::Value(data) => match data { - Field::StaticString(output) => assert_eq!(output, "one"), - _ => unreachable!("got {:?}: should have been static string", result1), - }, - _ => unreachable!("got {:?}, should have been value", result1), - } - let result2 = reply_iter.next().unwrap(); - match result2.get_field(&fieldname) { - CalcValue::Value(data) => match data { - Field::StaticString(output) => assert_eq!(output, "two"), - _ => unreachable!("got {:?}: should have been static string", result2), - }, - _ => unreachable!("got {:?}, should have been value", result2), - } - match reply_iter.next() { - None => {} - Some(_) => unreachable!("should be out of data"), - } - } -} - -#[derive(Clone, Debug)] -pub struct InternalRecord { - data: HashMap, -} - -impl InternalRecord { - pub fn new() -> Self { - Self { - data: HashMap::new(), - } - } - - pub fn insert(&mut self, id: Uuid, data: F) -> Field - where - F: Into, - { - match self.data.insert(id, data.into()) { - Some(data) => data.clone(), - None => Field::None, - } - } - - pub fn get(&self, id: &Uuid) -> Option<&Field> { - self.data.get(id) - } - - pub fn is_empty(&self) -> bool { - self.data.is_empty() - } -} - -#[derive(Clone, Debug)] -pub struct InternalRecords { - data: HashMap, -} - -impl InternalRecords { - pub fn new() -> Self { - Self { - data: HashMap::new(), - } - } - - pub fn insert(&mut self, oid: Oid, record: InternalRecord) -> Option { - self.data.insert(oid, record) - } - - pub fn get(&self, oid: &Oid) -> Option<&InternalRecord> { - self.data.get(oid) - } - - pub fn remove(&mut self, oid: &Oid) -> Option { - self.data.remove(oid) - } - - pub fn iter(&self) -> impl Iterator { - self.data.iter() - } - - pub fn keys(&self) -> impl Iterator { - self.data.keys() - } - - fn values(&self) -> impl Iterator { - self.data.values() - } - - pub fn contains_key(&self, oid: &Oid) -> bool { - self.data.contains_key(oid) - } - - fn len(&self) -> usize { - self.data.len() - } -} - -#[derive(Clone, Debug)] -pub struct Record { - names: Names, - data: InternalRecord, -} - -impl Record { - fn with_data(names: Names, rec: InternalRecord) -> Self { - Self { - names: names, - data: rec, - } - } - - pub fn get(&self, field_id: NT) -> Result - where - NT: Into, - { - let id = match self.names.get_id(field_id) { - Ok(data) => data, - Err(err) => return Err(err), - }; - match self.data.get(&id) { - Some(data) => Ok(data.clone()), - None => Err(MTTError::FieldMissingData), - } - } -} - -#[derive(Clone, Debug)] -pub struct Records { - names: Names, - data: InternalRecords, -} - -impl Records { - pub fn new(names: Names) -> Self { - Self { - names: names, - data: InternalRecords::new(), - } - } - - pub fn with_data(names: Names, records: InternalRecords) -> Self { - Self { - names: names, - data: records, - } - } - - pub fn insert(&mut self, oid: Oid, record: InternalRecord) -> Option { - self.data.insert(oid, record) - } - - pub fn len(&self) -> usize { - self.data.len() - } - - pub fn iter(&self) -> impl Iterator { - RecordIter::new(self) - } - - pub fn get_internal_records(&self) -> &InternalRecords { - &self.data - } -} - -struct RecordIter { - names: Names, - recs: Vec, -} - -impl RecordIter { - fn new(records: &Records) -> Self { - Self { - names: records.names.clone(), - recs: records.data.values().cloned().collect(), - } - } -} - -impl Iterator for RecordIter { - type Item = Record; - - fn next(&mut self) -> Option { - match self.recs.pop() { - Some(rec) => Some(Record::with_data(self.names.clone(), rec.clone())), - None => None, - } - } -} - -#[derive(Clone, Debug)] -pub struct Document { - data: HashMap, -} - -impl Document { - fn new() -> Self { - Self { - data: HashMap::new(), - } - } - - pub fn add_field(&mut self, name: NT, field: CV) - where - CV: Into, - NT: Into, - { - self.data.insert(name.into(), field.into()); - } - - fn get_field(&self, name: NT) -> &CalcValue - where - NT: Into, - { - match self.data.get(&name.into()) { - Some(data) => data, - None => &CalcValue::None, - } - } - - #[allow(dead_code)] - fn get_all(&self) -> Vec<(NameType, Field)> { - let mut output = Vec::new(); - for (key, value) in self.data.iter() { - output.push((key.clone(), value.get(&Field::None))); - } - output - } - - pub fn iter(&self) -> impl Iterator { - self.data.iter() - } -} - -#[cfg(test)] -mod documents { - use super::*; - use crate::name::Name; - - #[test] - fn can_add_static_string() { - let mut add = Document::new(); - let name = Name::english(Uuid::new_v4().to_string().as_str()); - let data = Uuid::new_v4().to_string(); - add.add_field(name.clone(), data.clone()); - let result = add.get_field(&name); - match result { - CalcValue::Value(holder) => match holder { - Field::StaticString(result) => assert_eq!(result, &data), - _ => unreachable!("got {:?}: should have received static string", holder), - }, - _ => unreachable!("got {:?}, should have been value", result), - } - } - - #[test] - fn can_add_uuid() { - let mut add = Document::new(); - let name = Name::english(Uuid::new_v4().to_string().as_str()); - let data = Uuid::new_v4(); - add.add_field(name.clone(), data.clone()); - let result = add.get_field(&name); - match result { - CalcValue::Value(holder) => match holder { - Field::Uuid(result) => assert_eq!(result, &data), - _ => unreachable!("got {:?}: should have received static string", holder), - }, - _ => unreachable!("got {:?}, should have been value", result), - } - } -} - -#[derive(Clone, Debug)] -pub struct Delete { - query: Query, -} - -impl Delete { - pub fn new(query: Query) -> Self { - Self { - query: query.into(), - } - } - - pub fn get_query(&self) -> &Query { - &self.query - } -} - -#[derive(Clone, Debug)] -pub struct Update { - query: Query, - values: Document, -} - -impl Update { - pub fn new(query: Query) -> Self { - Self { - query: query.into(), - values: Document::new(), - } - } - - pub fn get_query(&self) -> &Query { - &self.query - } - - pub fn get_values(&self) -> &Document { - &self.values - } - - pub fn get_values_mut(&mut self) -> &mut Document { - &mut self.values - } -} - -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct Oid { - oid: Uuid, -} - -impl Oid { - pub fn new() -> Self { - Self { - oid: Uuid::new_v4(), - } - } -} - -#[cfg(test)] -mod oids { - use super::*; - - #[test] - fn are_oids_random() { - let count = 10; - let mut holder: Vec = Vec::new(); - while holder.len() < count { - let result = Oid::new(); - assert!(!holder.contains(&result)); - holder.push(result); - } - } -} +pub mod wrapper; diff --git a/src/message/wrapper.rs b/src/message/wrapper.rs new file mode 100644 index 0000000..ba2f942 --- /dev/null +++ b/src/message/wrapper.rs @@ -0,0 +1,1688 @@ +use crate::{ + document::{ + definition::DocDef, + field::{Field, FieldType}, + }, + mtterror::MTTError, + name::{NameType, Names}, + queue::data_director::{Include, Path, Register, Route}, +}; +use chrono::prelude::*; +use std::{ + collections::{HashMap, HashSet}, + time::Duration, +}; +use uuid::Uuid; + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub enum Action { + Addition, + Create, + Delete, + Error, + GetLog, + Log, + OnAddition, + OnDelete, + OnQuery, + OnUpdate, + Query, + Records, + Register, + Reply, + Show, + Update, +} + +impl From for Action { + fn from(value: MsgAction) -> Self { + match value { + MsgAction::Addition(_) => Action::Addition, + MsgAction::Create(_) => Action::Create, + MsgAction::Delete(_) => Action::Delete, + MsgAction::Error(_) => Action::Error, + MsgAction::GetLog(_) => Action::GetLog, + MsgAction::OnAddition(_) => Action::OnAddition, + MsgAction::OnDelete(_) => Action::OnDelete, + MsgAction::OnQuery(_) => Action::OnQuery, + MsgAction::OnUpdate(_) => Action::OnUpdate, + MsgAction::Query(_) => Action::Query, + MsgAction::Records(_) => Action::Records, + MsgAction::Register(_) => Action::Register, + MsgAction::Reply(_) => Action::Reply, + MsgAction::Show => Action::Show, + MsgAction::Update(_) => Action::Update, + } + } +} + +impl From<&MsgAction> for Action { + fn from(value: &MsgAction) -> Self { + let action = value.clone(); + Self::from(action) + } +} + +#[derive(Clone, Debug)] +pub enum MsgAction { + Addition(Addition), + Create(DocDef), + // Alter + // Remove + Error(MTTError), + GetLog(Uuid), + OnAddition(Records), + OnDelete(Records), + OnQuery(Records), + OnUpdate(Records), + Query(Query), + Records(Records), + Register(Register), + Reply(Reply), + Show, + Delete(Delete), + Update(Update), +} + +impl From for MsgAction { + fn from(value: Addition) -> Self { + MsgAction::Addition(value) + } +} + +impl From for MsgAction { + fn from(value: Delete) -> Self { + MsgAction::Delete(value) + } +} + +impl From for MsgAction { + fn from(value: DocDef) -> Self { + MsgAction::Create(value) + } +} + +impl From for MsgAction { + fn from(value: MTTError) -> Self { + MsgAction::Error(value) + } +} + +impl From for MsgAction { + fn from(value: Query) -> Self { + MsgAction::Query(value) + } +} + +impl From for MsgAction { + fn from(value: Records) -> Self { + MsgAction::Records(value) + } +} + +impl From for MsgAction { + fn from(value: Register) -> Self { + MsgAction::Register(value) + } +} + +impl From for MsgAction { + fn from(value: Reply) -> Self { + MsgAction::Reply(value) + } +} + +impl From for MsgAction { + fn from(value: Update) -> Self { + MsgAction::Update(value) + } +} + +impl From for MsgAction { + fn from(value: Uuid) -> Self { + MsgAction::GetLog(value) + } +} + +impl From<&Uuid> for MsgAction { + fn from(value: &Uuid) -> Self { + Self::from(value.clone()) + } +} + +#[cfg(test)] +mod msgactions { + use super::*; + use crate::name::Name; + + #[test] + fn turn_document_definition_into_action() { + let name = Name::english(Uuid::new_v4().to_string().as_str()); + let value = DocDef::new(name.clone()); + let result: MsgAction = value.into(); + match result { + MsgAction::Create(def) => assert_eq!(def.get_document_names(), &[name].to_vec()), + _ => unreachable!("Got {:?}: dhould have been create", result), + } + } + + #[test] + fn turn_error_into_action() { + let data = "data".to_string(); + let value = MTTError::DocumentAlreadyExists(data.clone()); + let result: MsgAction = value.into(); + match result { + MsgAction::Error(result) => match result { + MTTError::DocumentAlreadyExists(output) => assert_eq!(output, data), + _ => unreachable!("Got {:?}: dhould have been create", result), + }, + _ => unreachable!("Got {:?}: dhould have been create", result), + } + let value = MTTError::DocumentNotFound(data.clone()); + let result: MsgAction = value.into(); + match result { + MsgAction::Error(result) => match result { + MTTError::DocumentNotFound(output) => assert_eq!(output, data), + _ => unreachable!("Got {:?}: dhould have been create", result), + }, + _ => unreachable!("Got {:?}: dhould have been create", result), + } + } + + #[test] + fn turn_query_into_action() { + let value = Query::new(); + let result: MsgAction = value.into(); + match result { + MsgAction::Query(_) => {} + _ => unreachable!("Got {:?}: dhould have been query", result), + } + } + + #[test] + fn turn_reply_into_action() { + let value = Reply::new(); + let result: MsgAction = value.into(); + match result { + MsgAction::Reply(_) => {} + _ => unreachable!("Got {:?}: dhould have been reply", result), + } + } +} + +#[derive(Clone, Debug)] +pub struct Message { + msg_id: Uuid, + document_id: NameType, + action: MsgAction, + route: Route, + // session: Option +} + +impl Message { + pub fn new(doc_id: D, action: A) -> Self + where + D: Into, + A: Into, + { + Self { + msg_id: Uuid::new_v4(), + document_id: doc_id.into(), + action: action.into(), + route: Route::default(), + } + } + + pub fn get_message_id(&self) -> &Uuid { + &self.msg_id + } + + pub fn get_action(&self) -> &MsgAction { + &self.action + } + + pub fn get_path(&self) -> Path { + Path::new( + Include::Just(self.msg_id.clone()), + Include::Just(self.document_id.clone()), + Include::Just(self.action.clone().into()), + ) + } + + pub fn get_route(&self) -> Route { + self.route.clone() + } + + pub fn set_route(&mut self, route: Route) { + self.route = route; + } + + pub fn response(&self, action: A) -> Self + where + A: Into, + { + Self { + msg_id: self.msg_id.clone(), + document_id: self.document_id.clone(), + action: action.into(), + route: Route::default(), + } + } + + pub fn forward(&self, doc_id: D, action: A) -> Self + where + D: Into, + A: Into, + { + Self { + msg_id: self.msg_id.clone(), + document_id: doc_id.into(), + action: action.into(), + route: Route::default(), + } + } +} + +#[cfg(test)] +mod messages { + use super::*; + use crate::name::Name; + + #[test] + fn can_the_document_be_a_named_reference() { + let dts = [Name::english("one"), Name::english("two")]; + for document in dts.into_iter() { + let msg = Message::new( + document.clone(), + MsgAction::Create(DocDef::new(document.clone())), + ); + match &msg.document_id { + NameType::Name(data) => assert_eq!(data, &document), + _ => unreachable!("should have been a string id"), + } + match msg.get_action() { + MsgAction::Create(_) => {} + _ => unreachable!("should have been a create document"), + } + } + } + + #[test] + fn can_the_document_be_an_id() { + let document = Uuid::new_v4(); + let msg = Message::new(document.clone(), Query::new()); + match msg.document_id { + NameType::ID(data) => assert_eq!(data, document), + _ => unreachable!("should have been an id"), + } + match msg.get_action() { + MsgAction::Query(_) => {} + _ => unreachable!("should have been an access query"), + } + } + + #[test] + fn do_messages_contain_routes() { + let mut msg = Message::new(Name::english("whatever"), Query::new()); + let default_route = msg.get_route(); + match default_route.msg_id { + Include::Just(_) => unreachable!("should defalt to all"), + Include::All => {} + } + match default_route.doc_id { + Include::Just(_) => unreachable!("should defalt to all"), + Include::All => {} + } + match default_route.action { + Include::Just(_) => unreachable!("should defalt to all"), + Include::All => {} + } + let doc_id = Uuid::new_v4(); + let route = Route::new( + Include::Just(msg.get_message_id().clone()), + Include::Just(doc_id.clone()), + Include::Just(msg.get_action().into()), + ); + msg.set_route(route); + let result = msg.get_route(); + match result.msg_id { + Include::Just(data) => assert_eq!(&data, msg.get_message_id()), + Include::All => unreachable!("should have message id"), + } + match result.doc_id { + Include::Just(data) => assert_eq!(data, doc_id), + Include::All => unreachable!("should have document id"), + } + match result.action { + Include::Just(data) => assert_eq!(data, msg.get_action().into()), + Include::All => unreachable!("should have action"), + } + } + + #[test] + fn is_the_message_id_random() { + let mut ids: Vec = Vec::new(); + for _ in 0..5 { + let msg = Message::new(Name::english("tester"), Query::new()); + let id = msg.get_message_id().clone(); + assert!(!ids.contains(&id), "{:?} containts {}", ids, id); + ids.push(id); + } + } + + #[test] + fn can_make_reply_message() { + let name = Name::english("testing"); + let msg = Message::new(name.clone(), Query::new()); + let responce = Reply::new(); + let reply = msg.response(responce); + assert_eq!(reply.get_message_id(), msg.get_message_id()); + match &reply.document_id { + NameType::Name(data) => assert_eq!(data, &name), + _ => unreachable!("should have been a name"), + } + match reply.get_action() { + MsgAction::Reply(_) => {} + _ => unreachable!("should have been a reply"), + } + } + + #[test] + fn can_make_error_message() { + let name = Name::english("testing"); + let msg = Message::new(name.clone(), Query::new()); + let err_msg = Uuid::new_v4().to_string(); + let result = msg.response(MTTError::DocumentNotFound(err_msg.clone())); + assert_eq!(result.get_message_id(), msg.get_message_id()); + match &result.document_id { + NameType::Name(data) => assert_eq!(data, &name), + _ => unreachable!("should have been a name"), + } + match result.get_action() { + MsgAction::Error(data) => match data { + MTTError::DocumentNotFound(txt) => assert_eq!(txt, &err_msg), + _ => unreachable!("got {:?}, should have received not found", data), + }, + _ => unreachable!("should have been a reply"), + } + } + + #[test] + fn can_make_a_response_message() { + let doc_id = Uuid::new_v4(); + let msg = Message::new(doc_id.clone(), Query::new()); + let data = Uuid::new_v4().to_string(); + let result1 = msg.response(MTTError::DocumentNotFound(data.clone())); + let result2 = msg.response(Reply::new()); + assert_eq!(result1.get_message_id(), msg.get_message_id()); + assert_eq!(result2.get_message_id(), msg.get_message_id()); + assert_eq!(result1.document_id, msg.document_id); + assert_eq!(result2.document_id, msg.document_id); + let action1 = result1.get_action(); + match action1 { + MsgAction::Error(err) => match err { + MTTError::DocumentNotFound(output) => assert_eq!(output, &data), + _ => unreachable!("got {:?}: should have received document not found", err), + }, + _ => unreachable!("got {:?}: should have received error", action1), + } + let action2 = result2.get_action(); + match action2 { + MsgAction::Reply(data) => assert_eq!(data.len(), 0), + _ => unreachable!("got {:?}: should have received a reply", action2), + } + } +} + +#[derive(Clone, Debug)] +pub struct Addition { + data: Document, +} + +impl Addition { + pub fn new() -> Self { + Self { + data: Document::new(), + } + } + + #[allow(dead_code)] + pub fn add_field(&mut self, name: NT, field: CV) + where + CV: Into, + NT: Into, + { + self.data.add_field(name, field); + } + + #[allow(dead_code)] + fn get_field(&self, name: NT) -> &CalcValue + where + NT: Into, + { + self.data.get_field(name) + } + + #[allow(dead_code)] + fn get_document(&self) -> Document { + self.data.clone() + } + + pub fn iter(&self) -> impl Iterator { + self.data.iter() + } +} + +#[cfg(test)] +mod additions { + use super::*; + use crate::name::Name; + + #[test] + fn can_add_static_string() { + let mut add = Addition::new(); + let name = Name::english(Uuid::new_v4().to_string().as_str()); + let data = Uuid::new_v4().to_string(); + add.add_field(name.clone(), data.clone()); + let result = add.get_field(&name); + match result { + CalcValue::Value(result) => match result { + Field::StaticString(output) => assert_eq!(output, &data), + _ => unreachable!("got {:?}, should have been a string", result), + }, + _ => unreachable!("got {:?}: should have received value", result), + } + } + + #[test] + fn can_add_uuid() { + let mut add = Addition::new(); + let name = Name::english(Uuid::new_v4().to_string().as_str()); + let data = Uuid::new_v4(); + add.add_field(name.clone(), data.clone()); + let output = add.get_field(&name); + match output { + CalcValue::Value(result) => match result { + Field::Uuid(result) => assert_eq!(result, &data), + _ => unreachable!("got {:?}: should have received uuid", result), + }, + _ => unreachable!("got {:?}: should have received value", output), + } + } + + #[test] + fn can_get_document() { + let mut add = Addition::new(); + let name = Name::english(Uuid::new_v4().to_string().as_str()); + let data = Uuid::new_v4(); + add.add_field(name.clone(), data.clone()); + let doc = add.get_document(); + let output = doc.get_field(&name); + match output { + CalcValue::Value(holder) => match holder { + Field::Uuid(result) => assert_eq!(result, &data), + _ => unreachable!("should have received uuid"), + }, + _ => unreachable!("got {:?}: should have received value", output), + } + } +} + +#[derive(Clone, Debug)] +pub enum Operand { + Add, + Equal, + GreaterThan, + GreaterThanEqual, + LessThan, + LessThanEqual, +} + +impl Operand { + #[allow(dead_code)] + fn validate(&self, x: &Field, y: &Field) -> bool { + match self { + Self::Equal => x == y, + Self::GreaterThan => x > y, + Self::GreaterThanEqual => x >= y, + Self::LessThan => x < y, + Self::LessThanEqual => x <= y, + _ => false, + } + } +} + +#[cfg(test)] +mod operands { + use super::*; + + #[test] + fn equals_true() { + let data: Field = Uuid::new_v4().into(); + assert!(Operand::Equal.validate(&data, &data)); + } + + #[test] + fn equals_false() { + let x: Field = Uuid::new_v4().into(); + let mut y: Field = Uuid::new_v4().into(); + while x == y { + y = Uuid::new_v4().into(); + } + assert!(!Operand::Equal.validate(&x, &y)); + } + + #[test] + fn does_greater() { + let data: Vec = vec![1.into(), 2.into(), 3.into()]; + assert!(!Operand::GreaterThan.validate(&data[0], &data[1])); + assert!(!Operand::GreaterThan.validate(&data[1], &data[1])); + assert!(Operand::GreaterThan.validate(&data[2], &data[1])); + } + + #[test] + fn does_greater_equal() { + let data: Vec = vec![1.into(), 2.into(), 3.into()]; + assert!(!Operand::GreaterThanEqual.validate(&data[0], &data[1])); + assert!(Operand::GreaterThanEqual.validate(&data[1], &data[1])); + assert!(Operand::GreaterThanEqual.validate(&data[2], &data[1])); + } + + #[test] + fn does_lesser() { + let data: Vec = vec![1.into(), 2.into(), 3.into()]; + assert!(Operand::LessThan.validate(&data[0], &data[1])); + assert!(!Operand::LessThan.validate(&data[1], &data[1])); + assert!(!Operand::LessThan.validate(&data[2], &data[1])); + } + + #[test] + fn does_lesser_equal() { + let data: Vec = vec![1.into(), 2.into(), 3.into()]; + assert!(Operand::LessThanEqual.validate(&data[0], &data[1])); + assert!(Operand::LessThanEqual.validate(&data[1], &data[1])); + assert!(!Operand::LessThanEqual.validate(&data[2], &data[1])); + } +} + +#[derive(Clone, Debug)] +pub enum CalcValue { + Calculate(Calculation), + Existing(FieldType), + FType(FieldType), + None, + Value(Field), +} + +impl CalcValue { + pub fn get(&self, existing: &Field) -> Field { + match self { + Self::Calculate(calc) => calc.calculate(existing), + Self::Existing(_) => existing.clone(), + Self::FType(ftype) => ftype.get_default(), + Self::None => Field::None, + Self::Value(field) => field.clone(), + } + } + + fn get_type(&self) -> FieldType { + match self { + Self::Calculate(calc) => calc.get_type(), + Self::Existing(ftype) => ftype.clone(), + Self::FType(ftype) => ftype.clone(), + Self::None => FieldType::None, + Self::Value(field) => field.into(), + } + } +} + +impl From for CalcValue { + fn from(value: Calculation) -> Self { + Self::Calculate(value) + } +} + +impl From for CalcValue { + fn from(value: Field) -> Self { + Self::Value(value) + } +} + +impl From<&Field> for CalcValue { + fn from(value: &Field) -> Self { + Self::from(value.clone()) + } +} + +impl From for CalcValue { + fn from(value: FieldType) -> Self { + Self::FType(value) + } +} + +impl From for CalcValue { + fn from(value: bool) -> Self { + let output: Field = value.into(); + Self::from(output).into() + } +} + +impl From> for CalcValue { + fn from(value: DateTime) -> Self { + let output: Field = value.into(); + Self::from(output).into() + } +} + +impl From for CalcValue { + fn from(value: Duration) -> Self { + let output: Field = value.into(); + Self::from(output).into() + } +} + +impl From for CalcValue { + fn from(value: i128) -> Self { + let output: Field = value.into(); + Self::from(output).into() + } +} + +impl From<&str> for CalcValue { + fn from(value: &str) -> Self { + let output: Field = value.into(); + Self::from(output).into() + } +} + +impl From for CalcValue { + fn from(value: String) -> Self { + let output: Field = value.into(); + Self::from(output).into() + } +} + +impl From for CalcValue { + fn from(value: Uuid) -> Self { + let output: Field = value.into(); + Self::from(output).into() + } +} + +#[cfg(test)] +mod calcvalues { + use super::*; + + #[test] + fn from_uuid() { + let value = Uuid::new_v4(); + let expected: Field = value.into(); + let result: CalcValue = value.into(); + match result.clone() { + CalcValue::Value(data) => assert_eq!(data, expected), + _ => unreachable!("got {:?}, should have gotten a field", result), + } + assert_eq!(result.get(&Field::None), expected); + } + + #[test] + fn from_str() { + let value = "something"; + let expected: Field = value.into(); + let result: CalcValue = value.into(); + match result.clone() { + CalcValue::Value(data) => assert_eq!(data, expected), + _ => unreachable!("got {:?}, should have gotten a field", result), + } + assert_eq!(result.get(&Field::None), expected); + } + + #[test] + fn from_string() { + let value = "data".to_string(); + let expected: Field = value.clone().into(); + let result: CalcValue = value.into(); + match result.clone() { + CalcValue::Value(data) => assert_eq!(data, expected), + _ => unreachable!("got {:?}, should have gotten a field", result), + } + assert_eq!(result.get(&Field::None), expected); + } + + #[test] + fn from_boolean() { + let value = true; + let expected: Field = value.clone().into(); + let result: CalcValue = value.into(); + match result.clone() { + CalcValue::Value(data) => assert_eq!(data, expected), + _ => unreachable!("got {:?}, should have gotten a field", result), + } + assert_eq!(result.get(&Field::None), expected); + } + + #[test] + fn from_datetime() { + let value = Utc::now(); + let expected: Field = value.clone().into(); + let result: CalcValue = value.into(); + match result.clone() { + CalcValue::Value(data) => assert_eq!(data, expected), + _ => unreachable!("got {:?}, should have gotten a field", result), + } + assert_eq!(result.get(&Field::None), expected); + } + + #[test] + fn from_duration() { + let value = Duration::from_secs(5); + let expected: Field = value.clone().into(); + let result: CalcValue = value.into(); + match result.clone() { + CalcValue::Value(data) => assert_eq!(data, expected), + _ => unreachable!("got {:?}, should have gotten a field", result), + } + assert_eq!(result.get(&Field::None), expected); + } + + #[test] + fn from_integer() { + let value: i128 = 5; + let expected: Field = value.clone().into(); + let result: CalcValue = value.into(); + match result.clone() { + CalcValue::Value(data) => assert_eq!(data, expected), + _ => unreachable!("got {:?}, should have gotten a field", result), + } + assert_eq!(result.get(&Field::None), expected); + } + + #[test] + fn from_calculation() { + let duration = Duration::from_secs(300); + let start = Utc::now() + duration; + let mut calc = Calculation::new(Operand::Add); + calc.add_value(FieldType::DateTime).unwrap(); + calc.add_value(duration.clone()).unwrap(); + let result: CalcValue = calc.into(); + let data = match result.get(&Field::None) { + Field::DateTime(data) => data, + _ => unreachable!(), + }; + let stop = Utc::now() + duration; + assert!( + data > start && data < stop, + "should be about 5 minutes ahead" + ); + } +} + +#[derive(Clone, Debug)] +pub struct Calculation { + operation: Operand, + values: Vec, +} + +impl Calculation { + pub fn new(operand: Operand) -> Self { + Self { + operation: operand, + values: Vec::new(), + } + } + + #[allow(dead_code)] + fn operation(&self) -> &Operand { + &self.operation + } + + #[allow(dead_code)] + fn get_fields(&self, existing: Field) -> Vec { + let mut output = Vec::new(); + for item in self.values.iter() { + output.push(item.get(&existing)); + } + output + } + + pub fn get_type(&self) -> FieldType { + if self.values.is_empty() { + FieldType::None + } else { + self.values[0].get_type() + } + } + + pub fn add_value(&mut self, data: CV) -> Result<(), MTTError> + where + CV: Into, + { + let holder: CalcValue = data.into(); + if self.values.is_empty() { + self.values.push(holder); + return Ok(()); + } + let mut base = self.get_type(); + match self.operation { + Operand::Add => match base { + FieldType::DateTime => base = FieldType::Duration, + _ => {} + }, + _ => {} + } + let ftype = holder.get_type(); + if base == ftype { + self.values.push(holder); + } else { + return Err(MTTError::DocumentFieldWrongDataType(base, ftype)); + } + Ok(()) + } + + #[allow(dead_code)] + fn validate_value(&self, value: CV) -> Result<(), MTTError> + where + CV: Into, + { + if self.values.is_empty() { + return Ok(()); + } + let holder = value.into(); + let mut base = self.get_type(); + match self.operation { + Operand::Add => { + if base == FieldType::DateTime { + base = FieldType::Duration; + } + } + _ => {} + } + let ftype = holder.get_type(); + if base == ftype { + Ok(()) + } else { + Err(MTTError::DocumentFieldWrongDataType(base, ftype)) + } + } + + pub fn calculate(&self, existing: &Field) -> Field { + let mut result = Field::None; + match self.operation { + Operand::Add => { + let mut first = true; + for value in self.values.iter() { + let data = value.get(existing); + if first { + result = data; + first = false; + } else { + result += data; + } + } + } + Operand::Equal => { + if self.values.len() >= 2 { + result = self.values[0] + .get(existing) + .equal(&self.values[1].get(existing)); + } + } + Operand::GreaterThan => { + if self.values.len() >= 2 { + result = self.values[0] + .get(existing) + .greater(&self.values[1].get(existing)); + } + } + Operand::GreaterThanEqual => { + if self.values.len() >= 2 { + result = self.values[0] + .get(existing) + .greater_equal(&self.values[1].get(existing)); + } + } + Operand::LessThan => { + if self.values.len() >= 2 { + result = self.values[0] + .get(existing) + .lesser(&self.values[1].get(existing)); + } + } + Operand::LessThanEqual => { + if self.values.len() >= 2 { + result = self.values[0] + .get(existing) + .lesser_equal(&self.values[1].get(existing)); + } + } + } + result + } +} + +#[cfg(test)] +mod calculations { + use super::*; + use rand::random; + + #[test] + fn errors_on_different_field_types() { + let mut calc = Calculation::new(Operand::Equal); + calc.add_value(Uuid::nil()).unwrap(); + match calc.add_value("other") { + Ok(_) => unreachable!("should have errored with wrong type"), + Err(err) => match err { + MTTError::DocumentFieldWrongDataType(expected, got) => { + assert_eq!(expected, FieldType::Uuid); + assert_eq!(got, FieldType::StaticString); + } + _ => unreachable!("got {:?}, expected wrong field type", err), + }, + } + } + + #[test] + fn returns_reference_to_operand() { + let calc = Calculation::new(Operand::Add); + match calc.operation() { + Operand::Add => {} + _ => unreachable!("got {:?}, shold have gotten assign", calc.operation()), + } + let calc = Calculation::new(Operand::Equal); + match calc.operation() { + Operand::Equal => {} + _ => unreachable!("got {:?}, shold have gotten assign", calc.operation()), + } + } + + #[test] + fn can_equal_true() { + let mut calc = Calculation::new(Operand::Equal); + let data: Field = Uuid::new_v4().into(); + calc.add_value(data.clone()).unwrap(); + calc.add_value(data.clone()).unwrap(); + let expected: Field = true.into(); + let result = calc.calculate(&Field::None); + assert_eq!(result, expected); + } + + #[test] + fn can_equal_false() { + let mut calc = Calculation::new(Operand::Equal); + let value1: Field = "fred".into(); + let value2: Field = "barney".into(); + calc.add_value(value1).unwrap(); + calc.add_value(value2).unwrap(); + let expected: Field = false.into(); + let result = calc.calculate(&Field::None); + assert_eq!(result, expected); + } + + #[test] + fn can_greater_than() { + let data: Vec<(Field, Field)> = vec![ + (0.into(), false.into()), + (1.into(), false.into()), + (2.into(), true.into()), + ]; + for (item, expected) in data.iter() { + let mut calc = Calculation::new(Operand::GreaterThan); + calc.add_value(item.clone()).unwrap(); + calc.add_value(data[1].0.clone()).unwrap(); + let result = calc.calculate(&Field::None); + assert_eq!(&result, expected); + } + } + + #[test] + fn can_greater_than_equal() { + let data: Vec<(Field, Field)> = vec![ + (0.into(), false.into()), + (1.into(), true.into()), + (2.into(), true.into()), + ]; + for (item, expected) in data.iter() { + let mut calc = Calculation::new(Operand::GreaterThanEqual); + calc.add_value(item.clone()).unwrap(); + calc.add_value(data[1].0.clone()).unwrap(); + let result = calc.calculate(&Field::None); + assert_eq!(&result, expected); + } + } + + #[test] + fn can_lesser_than() { + let data: Vec<(Field, Field)> = vec![ + (0.into(), true.into()), + (1.into(), false.into()), + (2.into(), false.into()), + ]; + for (item, expected) in data.iter() { + let mut calc = Calculation::new(Operand::LessThan); + calc.add_value(item.clone()).unwrap(); + calc.add_value(data[1].0.clone()).unwrap(); + let result = calc.calculate(&Field::None); + assert_eq!(&result, expected); + } + } + + #[test] + fn can_lesser_than_equal() { + let data: Vec<(Field, Field)> = vec![ + (0.into(), true.into()), + (1.into(), true.into()), + (2.into(), false.into()), + ]; + for (item, expected) in data.iter() { + let mut calc = Calculation::new(Operand::LessThanEqual); + calc.add_value(item.clone()).unwrap(); + calc.add_value(data[1].0.clone()).unwrap(); + let result = calc.calculate(&Field::None); + assert_eq!(&result, expected); + } + } + + #[test] + fn can_add_numbers() { + let mut calc = Calculation::new(Operand::Add); + let value1: i128 = random::().into(); + let value2: i128 = random::().into(); + let expected: Field = { value1 + value2 }.into(); + let value1: Field = value1.into(); + let value2: Field = value2.into(); + calc.add_value(value1.clone()).unwrap(); + calc.add_value(value2.clone()).unwrap(); + let result = calc.calculate(&Field::None); + assert_eq!( + result, expected, + "{:?} plus {:?} should equal {:?}", + value1, value2, expected + ); + } + + #[test] + fn can_use_existing_values() { + let mut calc = Calculation::new(Operand::Add); + let value1: i128 = random::().into(); + let value2: i128 = random::().into(); + let expected: Field = { value1 + value2 }.into(); + let value1: Field = value1.into(); + let value2: Field = value2.into(); + calc.add_value(value1.clone()).unwrap(); + calc.add_value(CalcValue::Existing(FieldType::Integer)) + .unwrap(); + let result = calc.calculate(&value2); + assert_eq!( + result, expected, + "{:?} plus {:?} should equal {:?}", + value1, value2, expected + ); + } + + #[test] + fn returns_error_on_mismatch() { + let mut calc = Calculation::new(Operand::Add); + calc.add_value(Uuid::nil()).unwrap(); + match calc.add_value("mismatch") { + Ok(_) => unreachable!("should have returned an error"), + Err(err) => match err { + MTTError::DocumentFieldWrongDataType(expected, got) => { + assert_eq!(got, FieldType::StaticString); + assert_eq!(expected, FieldType::Uuid); + } + _ => unreachable!("got {:?}, expected wrong field type", err), + }, + } + } + + #[test] + fn datetime_accepts_duration() { + let mut calc = Calculation::new(Operand::Add); + let duration = Duration::from_secs(3600); + let start = Utc::now() + duration; + calc.add_value(FieldType::DateTime).unwrap(); + match calc.add_value(duration.clone()) { + Ok(_) => {} + Err(err) => unreachable!("got {:?}, should have returned normally", err), + } + let result = calc.calculate(&Field::None); + let stop = Utc::now() + duration; + match result { + Field::DateTime(data) => { + assert!(data > start); + assert!(data < stop); + } + _ => unreachable!("got {:?}, should have been datetime", result), + } + } +} + +#[allow(dead_code)] +#[derive(Clone, Debug)] +pub struct Operation { + field_name: String, + operation: Operand, + value: Field, +} + +#[allow(dead_code)] +impl Operation { + pub fn new(name: String, op: Operand, value: F) -> Self + where + F: Into, + { + Self { + field_name: name, + operation: op, + value: value.into(), + } + } + + fn which_field(&self) -> String { + self.field_name.clone() + } + + pub fn validate(&self, field: &Field) -> bool { + self.operation.validate(field, &self.value) + } +} + +#[allow(dead_code)] +#[derive(Clone, Debug)] +enum QueryType { + Query(Query), + Oids(HashSet), +} + +impl From for QueryType { + fn from(value: Query) -> Self { + QueryType::Query(value) + } +} + +impl From> for QueryType { + fn from(value: HashSet) -> Self { + QueryType::Oids(value) + } +} + +#[derive(Clone, Debug)] +pub struct Query { + data: HashMap, +} + +impl Query { + pub fn new() -> Self { + Self { + data: HashMap::new(), + } + } + + pub fn add(&mut self, name: NT, operation: Calculation) + where + NT: Into, + { + self.data.insert(name.into(), operation); + } + + #[allow(dead_code)] + fn get(&self, name: NT) -> Option + where + NT: Into, + { + match self.data.get(&name.into()) { + Some(calc) => Some(calc.clone()), + None => None, + } + } + + #[allow(dead_code)] + fn field_ids(&self) -> HashSet<&NameType> { + self.data.keys().collect() + } + + pub fn iter(&self) -> impl Iterator { + self.data.iter() + } +} + +#[cfg(test)] +mod queries { + use super::*; + use crate::name::Name; + + #[test] + fn holds_calculation_to_run_query() { + let name = Name::english(Uuid::new_v4().to_string().as_str()); + let data = Uuid::new_v4(); + let mut bad_data = data.clone(); + while bad_data == data { + bad_data = Uuid::new_v4(); + } + let mut query = Query::new(); + let mut calc = Calculation::new(Operand::Equal); + calc.add_value(data.clone()).unwrap(); + query.add(name.clone(), calc); + match query.get(&name) { + Some(op) => { + let expected: Field = true.into(); + let mut holder = op.clone(); + holder.add_value(data).unwrap(); + assert_eq!(holder.calculate(&Field::None), expected); + } + None => unreachable!("should have returned a calculation"), + } + match query.get(&name) { + Some(op) => { + let expected: Field = false.into(); + let mut holder = op.clone(); + holder.add_value(bad_data).unwrap(); + assert_eq!(holder.calculate(&Field::None), expected); + } + None => unreachable!("should have returned a calculation"), + } + } +} + +#[allow(dead_code)] +#[derive(Clone, Debug)] +pub struct Reply { + data: Vec, +} + +#[allow(dead_code)] +impl Reply { + pub fn new() -> Self { + Self { data: Vec::new() } + } + + fn add(&mut self, doc: Document) { + self.data.push(doc); + } + + pub fn len(&self) -> usize { + self.data.len() + } + + fn iter(&self) -> impl Iterator { + self.data.iter() + } +} + +#[cfg(test)] +mod replies { + use super::*; + use crate::name::Name; + + #[test] + fn is_new_empty() { + let reply = Reply::new(); + assert_eq!(reply.len(), 0, "should have no records"); + } + + #[test] + fn can_add_documents() { + let mut reply = Reply::new(); + let doc = Document::new(); + reply.add(doc.clone()); + assert_eq!(reply.len(), 1); + reply.add(doc.clone()); + assert_eq!(reply.len(), 2); + } + + #[test] + fn can_retrieve_documents() { + let fieldname = Name::english("field"); + let mut doc1 = Document::new(); + doc1.add_field(fieldname.clone(), "one"); + let mut doc2 = Document::new(); + doc2.add_field(fieldname.clone(), "two"); + let mut reply = Reply::new(); + reply.add(doc1); + reply.add(doc2); + let mut reply_iter = reply.iter(); + let result1 = reply_iter.next().unwrap(); + match result1.get_field(&fieldname) { + CalcValue::Value(data) => match data { + Field::StaticString(output) => assert_eq!(output, "one"), + _ => unreachable!("got {:?}: should have been static string", result1), + }, + _ => unreachable!("got {:?}, should have been value", result1), + } + let result2 = reply_iter.next().unwrap(); + match result2.get_field(&fieldname) { + CalcValue::Value(data) => match data { + Field::StaticString(output) => assert_eq!(output, "two"), + _ => unreachable!("got {:?}: should have been static string", result2), + }, + _ => unreachable!("got {:?}, should have been value", result2), + } + match reply_iter.next() { + None => {} + Some(_) => unreachable!("should be out of data"), + } + } +} + +#[derive(Clone, Debug)] +pub struct InternalRecord { + data: HashMap, +} + +impl InternalRecord { + pub fn new() -> Self { + Self { + data: HashMap::new(), + } + } + + pub fn insert(&mut self, id: Uuid, data: F) -> Field + where + F: Into, + { + match self.data.insert(id, data.into()) { + Some(data) => data.clone(), + None => Field::None, + } + } + + pub fn get(&self, id: &Uuid) -> Option<&Field> { + self.data.get(id) + } + + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } +} + +#[derive(Clone, Debug)] +pub struct InternalRecords { + data: HashMap, +} + +impl InternalRecords { + pub fn new() -> Self { + Self { + data: HashMap::new(), + } + } + + pub fn insert(&mut self, oid: Oid, record: InternalRecord) -> Option { + self.data.insert(oid, record) + } + + pub fn get(&self, oid: &Oid) -> Option<&InternalRecord> { + self.data.get(oid) + } + + pub fn remove(&mut self, oid: &Oid) -> Option { + self.data.remove(oid) + } + + pub fn iter(&self) -> impl Iterator { + self.data.iter() + } + + pub fn keys(&self) -> impl Iterator { + self.data.keys() + } + + fn values(&self) -> impl Iterator { + self.data.values() + } + + pub fn contains_key(&self, oid: &Oid) -> bool { + self.data.contains_key(oid) + } + + fn len(&self) -> usize { + self.data.len() + } +} + +#[derive(Clone, Debug)] +pub struct Record { + names: Names, + data: InternalRecord, +} + +impl Record { + fn with_data(names: Names, rec: InternalRecord) -> Self { + Self { + names: names, + data: rec, + } + } + + pub fn get(&self, field_id: NT) -> Result + where + NT: Into, + { + let id = match self.names.get_id(field_id) { + Ok(data) => data, + Err(err) => return Err(err), + }; + match self.data.get(&id) { + Some(data) => Ok(data.clone()), + None => Err(MTTError::FieldMissingData), + } + } +} + +#[derive(Clone, Debug)] +pub struct Records { + names: Names, + data: InternalRecords, +} + +impl Records { + pub fn new(names: Names) -> Self { + Self { + names: names, + data: InternalRecords::new(), + } + } + + pub fn with_data(names: Names, records: InternalRecords) -> Self { + Self { + names: names, + data: records, + } + } + + pub fn insert(&mut self, oid: Oid, record: InternalRecord) -> Option { + self.data.insert(oid, record) + } + + pub fn len(&self) -> usize { + self.data.len() + } + + pub fn iter(&self) -> impl Iterator { + RecordIter::new(self) + } + + pub fn get_internal_records(&self) -> &InternalRecords { + &self.data + } +} + +struct RecordIter { + names: Names, + recs: Vec, +} + +impl RecordIter { + fn new(records: &Records) -> Self { + Self { + names: records.names.clone(), + recs: records.data.values().cloned().collect(), + } + } +} + +impl Iterator for RecordIter { + type Item = Record; + + fn next(&mut self) -> Option { + match self.recs.pop() { + Some(rec) => Some(Record::with_data(self.names.clone(), rec.clone())), + None => None, + } + } +} + +#[derive(Clone, Debug)] +pub struct Document { + data: HashMap, +} + +impl Document { + fn new() -> Self { + Self { + data: HashMap::new(), + } + } + + pub fn add_field(&mut self, name: NT, field: CV) + where + CV: Into, + NT: Into, + { + self.data.insert(name.into(), field.into()); + } + + fn get_field(&self, name: NT) -> &CalcValue + where + NT: Into, + { + match self.data.get(&name.into()) { + Some(data) => data, + None => &CalcValue::None, + } + } + + #[allow(dead_code)] + fn get_all(&self) -> Vec<(NameType, Field)> { + let mut output = Vec::new(); + for (key, value) in self.data.iter() { + output.push((key.clone(), value.get(&Field::None))); + } + output + } + + pub fn iter(&self) -> impl Iterator { + self.data.iter() + } +} + +#[cfg(test)] +mod documents { + use super::*; + use crate::name::Name; + + #[test] + fn can_add_static_string() { + let mut add = Document::new(); + let name = Name::english(Uuid::new_v4().to_string().as_str()); + let data = Uuid::new_v4().to_string(); + add.add_field(name.clone(), data.clone()); + let result = add.get_field(&name); + match result { + CalcValue::Value(holder) => match holder { + Field::StaticString(result) => assert_eq!(result, &data), + _ => unreachable!("got {:?}: should have received static string", holder), + }, + _ => unreachable!("got {:?}, should have been value", result), + } + } + + #[test] + fn can_add_uuid() { + let mut add = Document::new(); + let name = Name::english(Uuid::new_v4().to_string().as_str()); + let data = Uuid::new_v4(); + add.add_field(name.clone(), data.clone()); + let result = add.get_field(&name); + match result { + CalcValue::Value(holder) => match holder { + Field::Uuid(result) => assert_eq!(result, &data), + _ => unreachable!("got {:?}: should have received static string", holder), + }, + _ => unreachable!("got {:?}, should have been value", result), + } + } +} + +#[derive(Clone, Debug)] +pub struct Delete { + query: Query, +} + +impl Delete { + pub fn new(query: Query) -> Self { + Self { + query: query.into(), + } + } + + pub fn get_query(&self) -> &Query { + &self.query + } +} + +#[derive(Clone, Debug)] +pub struct Update { + query: Query, + values: Document, +} + +impl Update { + pub fn new(query: Query) -> Self { + Self { + query: query.into(), + values: Document::new(), + } + } + + pub fn get_query(&self) -> &Query { + &self.query + } + + pub fn get_values(&self) -> &Document { + &self.values + } + + pub fn get_values_mut(&mut self) -> &mut Document { + &mut self.values + } +} + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Oid { + oid: Uuid, +} + +impl Oid { + pub fn new() -> Self { + Self { + oid: Uuid::new_v4(), + } + } +} + +#[cfg(test)] +mod oids { + use super::*; + + #[test] + fn are_oids_random() { + let count = 10; + let mut holder: Vec = Vec::new(); + while holder.len() < count { + let result = Oid::new(); + assert!(!holder.contains(&result)); + holder.push(result); + } + } +} diff --git a/src/queue/data_director.rs b/src/queue/data_director.rs index 4f26f4f..409d79f 100644 --- a/src/queue/data_director.rs +++ b/src/queue/data_director.rs @@ -1,5 +1,5 @@ use crate::{ - message::{Action, Message, MsgAction}, + message::wrapper::{Action, Message, MsgAction}, mtterror::MTTError, name::{Name, NameType, Names}, queue::router::Queue, @@ -120,7 +120,7 @@ impl Path { mod paths { use super::*; use crate::{ - message::{MsgAction, Records}, + message::wrapper::{MsgAction, Records}, name::{Name, Names}, }; diff --git a/src/queue/router.rs b/src/queue/router.rs index 805012c..7b1e1ee 100644 --- a/src/queue/router.rs +++ b/src/queue/router.rs @@ -1,5 +1,5 @@ use crate::{ - message::Message, + message::wrapper::Message, name::NameType, queue::data_director::{DocRegistry, RegMsg, Register}, }; @@ -97,7 +97,7 @@ impl Queue { mod routers { use super::*; use crate::{ - message::{MsgAction, Query}, + message::wrapper::{MsgAction, Query}, name::Name, support_tests::TIMEOUT, }; @@ -242,7 +242,7 @@ mod routers { mod queues { use super::*; use crate::{ - message::MsgAction, + message::wrapper::MsgAction, mtterror::MTTError, name::Name, queue::data_director::{Include, Path},