diff --git a/src/document/create.rs b/src/document/create.rs index 7eb527d..1b7299c 100644 --- a/src/document/create.rs +++ b/src/document/create.rs @@ -5,9 +5,9 @@ use crate::{ definition::{DocDef, DocFuncType}, field::Field, }, - message::wrapper::Message, + message::{wrapper::Message, MessageAction}, mtterror::{ErrorID, MTTError}, - name::NameType, + name::{NameID, NameType}, queue::{ data_director::{Include, Path, RegMsg, Register, RouteID}, router::Queue, @@ -171,11 +171,11 @@ impl Index { } struct Indexes { - data: HashMap, + data: HashMap, } impl Indexes { - fn new(settings: &HashMap) -> Self { + fn new(settings: &HashMap) -> Self { let mut output = HashMap::new(); for (key, value) in settings.iter() { output.insert(key.clone(), value.create_index()); @@ -183,15 +183,20 @@ impl Indexes { Self { data: output } } - fn index_ids(&self) -> HashSet<&Uuid> { - self.data.keys().collect::>() + fn index_ids(&self) -> HashSet<&NameID> { + self.data.keys().collect::>() } - fn pull(&self, field_id: &Uuid, calc: &Calculation) -> Result, MTTError> { + fn pull(&self, field_id: &NameID, calc: &Calculation) -> Result, MTTError> { self.data.get(field_id).unwrap().pull(calc) } - fn add_to_index(&mut self, field_name: &Uuid, field: Field, oid: Oid) -> Result<(), MTTError> { + fn add_to_index( + &mut self, + field_name: &NameID, + field: Field, + oid: Oid, + ) -> Result<(), MTTError> { let index = match self.data.get_mut(field_name) { Some(data) => data, None => return Ok(()), @@ -199,7 +204,7 @@ impl Indexes { index.add(field, oid) } - fn validate(&self, field_name: &Uuid, value: &Field) -> Result<(), MTTError> { + fn validate(&self, field_name: &NameID, value: &Field) -> Result<(), MTTError> { match self.data.get(field_name) { Some(index) => match index.validate(value) { Ok(_) => {} @@ -210,7 +215,7 @@ impl Indexes { Ok(()) } - fn iter_mut(&mut self) -> impl Iterator { + fn iter_mut(&mut self) -> impl Iterator { self.data.iter_mut() } } @@ -361,7 +366,7 @@ struct DocumentFile { docdef: DocDef, docs: InternalRecords, indexes: Indexes, - name_id: Uuid, + name_id: NameID, queue: Queue, routes: HashMap, rx: Receiver, @@ -373,7 +378,7 @@ impl DocumentFile { rx: Receiver, docdef: DocDef, routes: HashMap, - name_id: Uuid, + name_id: NameID, ) -> Self { let indexes = Indexes::new(docdef.get_indexes()); Self { @@ -472,11 +477,12 @@ impl DocumentFile { where NT: Into, { - let field_id = match self.docdef.get_field_id(field_name) { + let id_holder = field_name.into(); + let field_id = match self.docdef.get_field_id(id_holder.clone()) { Ok(data) => data, Err(err) => return Err(err), }; - let output = match self.docdef.validate(field_id.clone(), value) { + let output = match self.docdef.validate(id_holder.clone(), value) { Ok(data) => data, Err(err) => return Err(err), }; @@ -493,10 +499,17 @@ impl DocumentFile { _ => return, }; let mut holder = InternalRecord::new(); + + let mut field_ids = self.docdef.get_field_ids(); + println!("{:?}", field_ids); + for (name_id, value) in addition.iter() {} + for (name_id, value) in addition.iter() { let field_id = match self.docdef.get_field_id(name_id) { Ok(id) => id, - Err(err) => { + Err(mut err) => { + err.add_parent(ErrorID::Field(name_id.clone())); + err.add_parent(ErrorID::Document(msg.doc_name().clone())); let reply = msg.response(err); self.queue.send(reply); return; @@ -504,14 +517,16 @@ impl DocumentFile { }; holder.insert(field_id.clone(), value.get(&Field::None)); } - for field_id in self.docdef.field_ids().iter() { + for field_id in self.docdef.get_field_ids().iter() { let value = match holder.get(field_id) { Some(data) => data, None => &Field::None, }; let corrected = match self.validate(field_id, value) { Ok(data) => data, - Err(err) => { + Err(mut err) => { + err.add_parent(ErrorID::Field(field_id.clone().into())); + err.add_parent(ErrorID::Document(msg.doc_name().clone())); let reply = msg.response(err); self.queue.send(reply); return; @@ -570,8 +585,8 @@ impl DocumentFile { fn run_query(&self, query: &Query) -> Result { let indexed_ids = self.indexes.index_ids(); - let mut indexed: HashMap = HashMap::new(); - let mut unindexed: HashMap = HashMap::new(); + let mut indexed: HashMap = HashMap::new(); + let mut unindexed: HashMap = HashMap::new(); for (field, data) in query.iter() { let id = match self.docdef.get_field_id(field) { Ok(fid) => fid, @@ -647,7 +662,7 @@ impl DocumentFile { update: &Update, msg: &Message, ) -> Result { - let mut changes: HashMap = HashMap::new(); + let mut changes: HashMap = HashMap::new(); for (key, value) in update.get_values().iter() { let field_id = match self.docdef.get_field_id(key) { Ok(data) => data, @@ -1125,7 +1140,6 @@ mod document_files { } assert!(entries.is_empty(), "did not use {:?}", entries); } - */ #[test] fn errors_on_wrong_field_name() { @@ -1145,8 +1159,10 @@ mod document_files { _ => unreachable!("got {:?}: should have been an error", result.get_action()), } } + */ #[test] + #[ignore = "move to lib"] fn errors_on_wrong_field_type() { let mut test_doc = TestDocument::new([FieldType::Uuid].to_vec()); test_doc.start(standard_paths()); @@ -1769,6 +1785,7 @@ mod document_files { } #[test] + #[ignore = "move to lib"] fn update_errors_on_bad_field_type() { let mut doc = TestDocument::new([FieldType::Uuid, FieldType::StaticString].to_vec()); doc.start(standard_paths()); diff --git a/src/document/definition.rs b/src/document/definition.rs index 435a01c..af8c550 100644 --- a/src/document/definition.rs +++ b/src/document/definition.rs @@ -3,7 +3,7 @@ use crate::{ document::create::IndexType, message::MessageAction, mtterror::{ErrorID, MTTError}, - name::{Name, NameType, Names}, + name::{Name, NameID, NameType, Names}, queue::data_director::{Include, Path}, }; use std::collections::{HashMap, HashSet}; @@ -62,7 +62,7 @@ impl FieldSetting { _ => { let vft: FieldType = value.into(); if vft != self.fieldtype { - let err = MTTError::new(ErrorID::FieldInvalidType); + let err = MTTError::new(ErrorID::FieldTypeExpected(self.fieldtype.clone())); return Err(err); } Ok(value.clone()) @@ -90,12 +90,13 @@ mod fieldsettings { #[test] fn validates_for_bad_field_type() { - let fset = FieldSetting::new(FieldType::Uuid); + let test_type = FieldType::Uuid; + let fset = FieldSetting::new(test_type.clone()); let value: Field = "text".into(); match fset.validate(&value) { Ok(data) => unreachable!("got {:?}: should have gotten an error", data), Err(err) => match err.get_error_ids().back().unwrap() { - ErrorID::FieldInvalidType => {} + ErrorID::FieldTypeExpected(data) => assert_eq!(data, &test_type), _ => unreachable!("got {:?}: should have gotten a value", err), }, } @@ -201,8 +202,8 @@ impl PathAction { pub struct DocDef { doc_names: Vec, field_names: Names, - fields: HashMap, - indexes: HashMap, + fields: HashMap, + indexes: HashMap, routes: Vec, } @@ -272,7 +273,10 @@ impl DocDef { &self.field_names } - #[allow(dead_code)] + pub fn get_field_ids(&self) -> HashSet { + self.field_names.get_ids() + } + fn get_field_names_mut(&mut self) -> &mut Names { &mut self.field_names } @@ -282,7 +286,7 @@ impl DocDef { self.fields.insert(id, FieldSetting::new(ftype)); } - pub fn get_field_id(&self, field_name: NT) -> Result + pub fn get_field_id(&self, field_name: NT) -> Result where NT: Into, { @@ -292,7 +296,6 @@ impl DocDef { } } - #[allow(dead_code)] fn get_field(&self, field_name: NT) -> Result<&FieldSetting, MTTError> where NT: Into, @@ -304,7 +307,6 @@ impl DocDef { Ok(self.fields.get(&id).unwrap()) } - #[allow(dead_code)] fn get_field_mut(&mut self, field_name: NT) -> Result<&mut FieldSetting, MTTError> where NT: Into, @@ -316,7 +318,7 @@ impl DocDef { Ok(self.fields.get_mut(&id).unwrap()) } - pub fn field_ids(&self) -> HashSet { + pub fn field_ids(&self) -> HashSet { self.fields.keys().cloned().collect() } @@ -354,12 +356,11 @@ impl DocDef { Ok(()) } - pub fn get_indexes(&self) -> &HashMap { + pub fn get_indexes(&self) -> &HashMap { &self.indexes } - #[allow(dead_code)] - fn iter(&self) -> impl Iterator { + fn iter(&self) -> impl Iterator { self.fields.iter() } diff --git a/src/document/record.rs b/src/document/record.rs index a1e2251..375b1b8 100644 --- a/src/document/record.rs +++ b/src/document/record.rs @@ -2,7 +2,7 @@ use crate::{ action::Field, message::MessageAction, mtterror::{ErrorID, MTTError}, - name::{Name, NameType, Names}, + name::{Name, NameID, NameType, Names}, }; use std::collections::HashMap; use uuid::Uuid; @@ -38,7 +38,7 @@ mod oids { #[derive(Clone, Debug)] pub struct InternalRecord { - data: HashMap, + data: HashMap, } impl InternalRecord { @@ -48,7 +48,7 @@ impl InternalRecord { } } - pub fn insert(&mut self, id: Uuid, data: F) -> Field + pub fn insert(&mut self, id: NameID, data: F) -> Field where F: Into, { @@ -58,7 +58,7 @@ impl InternalRecord { } } - pub fn get(&self, id: &Uuid) -> Option<&Field> { + pub fn get(&self, id: &NameID) -> Option<&Field> { self.data.get(id) } diff --git a/src/lib.rs b/src/lib.rs index edcf236..7b3d859 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,7 +134,7 @@ impl MoreThanText { return Err(error); } _ => {} - } + }, _ => unreachable!("got {:?} should have been a registry message", action), } } diff --git a/src/message/wrapper.rs b/src/message/wrapper.rs index 4b62a72..9760745 100644 --- a/src/message/wrapper.rs +++ b/src/message/wrapper.rs @@ -90,7 +90,10 @@ impl MessageAction for Message { #[cfg(test)] mod messages { use super::*; - use crate::{action::DocDef, name::Name}; + use crate::{ + action::DocDef, + name::{name_id_support::test_name_id, Name}, + }; #[test] fn can_the_document_be_a_named_reference() { @@ -106,7 +109,7 @@ mod messages { #[test] fn can_the_document_be_an_id() { - let document = Uuid::new_v4(); + let document = test_name_id(); let msg = Message::new(Query::new(document.clone())); match msg.get_action() { MsgAction::Query(_) => {} @@ -131,7 +134,7 @@ mod messages { Include::Just(_) => unreachable!("should defalt to all"), Include::All => {} } - let doc_id = Uuid::new_v4(); + let doc_id = test_name_id(); let route = Route::new( Include::Just(msg.get_message_id().clone()), Include::Just(doc_id.clone()), @@ -195,7 +198,7 @@ mod messages { #[test] fn can_make_a_response_message() { - let doc_id = Uuid::new_v4(); + let doc_id = test_name_id(); let msg = Message::new(Query::new(doc_id.clone())); let data = Uuid::new_v4().to_string(); let result1 = msg.response(MTTError::new(ErrorID::DocumentNotFound)); diff --git a/src/mtterror.rs b/src/mtterror.rs index 78ae23b..8b5d381 100644 --- a/src/mtterror.rs +++ b/src/mtterror.rs @@ -12,11 +12,13 @@ pub enum ErrorID { Document(NameType), DocumentNameAlreadyExists, DocumentNotFound, + Field(NameType), FieldDataMustBeUnique, FieldInvalidNone, FieldInvalidType, FieldMissingData, FieldNameAlreadyExists, + FieldTypeExpected(FieldType), IndexEntryAlreadyExists, InvalidFieldName(Name), NameAlreadyExists, diff --git a/src/name.rs b/src/name.rs index ae2b310..93ba12f 100644 --- a/src/name.rs +++ b/src/name.rs @@ -1,11 +1,14 @@ use crate::mtterror::{ErrorID, MTTError}; use isolang::Language; -use std::{collections::HashMap, fmt}; +use std::{ + collections::{HashMap, HashSet}, + fmt, +}; use uuid::Uuid; #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub enum NameType { - ID(Uuid), + ID(NameID), Name(Name), None, } @@ -29,14 +32,14 @@ impl From<&Name> for NameType { } } -impl From for NameType { - fn from(value: Uuid) -> Self { +impl From for NameType { + fn from(value: NameID) -> Self { Self::ID(value) } } -impl From<&Uuid> for NameType { - fn from(value: &Uuid) -> Self { +impl From<&NameID> for NameType { + fn from(value: &NameID) -> Self { let id = value.clone(); Self::from(id) } @@ -84,10 +87,48 @@ pub mod test_support { } } +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct NameID { + data: Uuid, +} + +impl NameID { + fn new() -> Self { + Self { + data: Uuid::new_v4(), + } + } + + fn nil() -> Self { + Self { data: Uuid::nil() } + } +} + +#[cfg(test)] +pub mod name_id_support { + use super::*; + + pub fn test_name_id() -> NameID { + NameID::new() + } +} + +#[cfg(test)] +mod name_ids { + use super::*; + + #[test] + fn are_name_ids_random() { + let id1 = NameID::new(); + let id2 = NameID::new(); + assert_ne!(id1, id2); + } +} + #[derive(Clone, Debug, PartialEq)] pub struct Names { - names: HashMap, - ids: HashMap>, + names: HashMap, + ids: HashMap>, } impl Names { @@ -98,7 +139,7 @@ impl Names { } } - pub fn add_names(&mut self, names: Vec) -> Result { + pub fn add_names(&mut self, names: Vec) -> Result { let mut languages: Vec<&Language> = Vec::new(); for name in names.iter() { let lang = name.get_language(); @@ -113,9 +154,9 @@ impl Names { return Err(err); } } - let mut id = Uuid::new_v4(); + let mut id = NameID::new(); while self.ids.contains_key(&id) { - id = Uuid::new_v4(); + id = NameID::new(); } for name in names.iter() { self.names.insert(name.clone(), id.clone()); @@ -126,7 +167,7 @@ impl Names { Ok(id) } - pub fn get_id(&self, name: NT) -> Result + pub fn get_id(&self, name: NT) -> Result where NT: Into, { @@ -140,16 +181,20 @@ impl Names { if self.ids.contains_key(&data) { Ok(data) } else { - if data == Uuid::nil() { + if data == NameID::nil() { Ok(data) } else { Err(MTTError::new(ErrorID::NameNotFound(name_type))) } } } - NameType::None => Ok(Uuid::nil()), + NameType::None => Ok(NameID::nil()), } } + + pub fn get_ids(&self) -> HashSet { + self.ids.keys().cloned().collect() + } } #[cfg(test)] @@ -173,7 +218,7 @@ mod names { let mut names = Names::new(); let id = names.add_names(vec![name.clone()]).unwrap(); assert_eq!(names.get_id(name).unwrap(), id); - assert_eq!(names.get_id(id).unwrap(), id); + assert_eq!(names.get_id(&id).unwrap(), id); } #[test] @@ -192,7 +237,7 @@ mod names { fn are_name_ids_unique() { let mut names = Names::new(); let data = ["one", "two", "three", "four", "five"]; - let mut ids: HashSet = HashSet::new(); + let mut ids: HashSet = HashSet::new(); for item in data.iter() { let name = Name::english(item); ids.insert(names.add_names([name].to_vec()).unwrap()); @@ -245,7 +290,7 @@ mod names { #[test] fn errors_on_bad_id() { - let id = Uuid::new_v4(); + let id = NameID::new(); let expected: NameType = id.clone().into(); let names = Names::new(); match names.get_id(id.clone()) { @@ -256,4 +301,25 @@ mod names { }, } } + + #[test] + fn able_to_get_name_ids() { + let count = 5; + let mut data: Vec = Vec::new(); + for i in 0..count { + let name = Name::english(format!("name{}", i).as_str()); + data.push(name); + } + let mut names = Names::new(); + for name in data.iter() { + names.add_names(vec![name.clone()]).unwrap(); + } + let mut result = names.get_ids(); + assert_eq!(result.len(), count); + for name in data.iter() { + let id = names.get_id(name).unwrap(); + assert!(result.remove(&id), "id {:?} was missing", id); + } + assert_eq!(result.len(), 0, "still has {:?} ids", result); + } } diff --git a/src/queue/data_director.rs b/src/queue/data_director.rs index 5fb7e8e..385a5db 100644 --- a/src/queue/data_director.rs +++ b/src/queue/data_director.rs @@ -2,7 +2,7 @@ use crate::{ action::{Action, MsgAction}, message::{wrapper::Message, MessageAction}, mtterror::MTTError, - name::{Name, NameType, Names}, + name::{Name, NameID, NameType, Names}, queue::router::Queue, }; use std::{ @@ -51,7 +51,7 @@ mod includes { pub enum RegMsg { AddRoute(Path), AddDocName(Vec), - DocumentNameID(Uuid), + DocumentNameID(NameID), Error(MTTError), GetNameID(Name), Ok, @@ -94,13 +94,15 @@ impl MessageAction for Register {} #[cfg(test)] mod registries { use super::*; + use crate::name::name_id_support::test_name_id; #[test] fn does_registry_store_data() { - let id = Uuid::new_v4(); + let name_id = test_name_id(); + let sender_data_id = Uuid::new_v4(); let inputs = [ - RegMsg::DocumentNameID(id.clone()), - RegMsg::RemoveSender(id.clone()), + RegMsg::DocumentNameID(name_id.clone()), + RegMsg::RemoveSender(sender_data_id.clone()), ]; for regmsg in inputs.iter() { let sender_id = Uuid::new_v4(); @@ -108,7 +110,8 @@ mod registries { assert_eq!(reg.doc_name(), &NameType::None); assert_eq!(reg.get_sender_id(), &sender_id); match reg.get_msg() { - RegMsg::DocumentNameID(data) | RegMsg::RemoveSender(data) => assert_eq!(data, &id), + RegMsg::DocumentNameID(data) => assert_eq!(data, &name_id), + RegMsg::RemoveSender(data) => assert_eq!(data, &sender_data_id), _ => unreachable!("should have been one of the inputs"), } } @@ -196,12 +199,12 @@ mod paths { #[derive(Clone, Debug, PartialEq)] pub struct Route { pub action: Include, - pub doc_id: Include, + pub doc_id: Include, pub msg_id: Include, } impl Route { - pub fn new(msg_id: Include, doc: Include, action: Include) -> Self { + pub fn new(msg_id: Include, doc: Include, action: Include) -> Self { Self { action: action, doc_id: doc, @@ -248,7 +251,7 @@ impl From<&RouteID> for Route { #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct RouteID { action: Option, - doc_id: Option, + doc_id: Option, msg_id: Option, } diff --git a/tests/add_test.rs b/tests/add_test.rs index f156d9f..bf768a3 100644 --- a/tests/add_test.rs +++ b/tests/add_test.rs @@ -51,23 +51,38 @@ fn does_it_error_on_a_bad_document_name() { let add = Addition::new(doc_name.clone()); let result = mtt.records(add).unwrap_err(); assert_eq!(result.to_string(), expected.to_string()); - - - - /* - let result = mtt - .records(add) - .unwrap_err() - .get_error_ids() - .back() - .unwrap() - .clone(); - match result { - ErrorID::NameNotFound(_) => {} - _ => unreachable!( - "got {:?}: should have been document field not found.", - result - ), - } - */ +} + +#[test] +fn does_it_error_on_bad_field_name() { + let mut mtt = MoreThanText::new(); + let doc_name = Name::english("holder"); + let field_name = Name::english("missing"); + let docdef = DocDef::new(doc_name.clone()); + mtt.create_document(docdef); + let mut add = Addition::new(doc_name.clone()); + add.add_field(field_name.clone(), "something"); + let mut expected = MTTError::new(ErrorID::NameNotFound(field_name.clone().into())); + expected.add_parent(ErrorID::Field(field_name.clone().into())); + expected.add_parent(ErrorID::Document(doc_name.clone().into())); + let result = mtt.records(add).unwrap_err(); + assert_eq!(result.to_string(), expected.to_string()); +} + +#[test] +#[ignore = "Returning name id not name"] +fn does_it_error_on_bad_field_type() { + let mut mtt = MoreThanText::new(); + let doc_name = Name::english("holder"); + let field_name = Name::english("missing"); + let mut docdef = DocDef::new(doc_name.clone()); + docdef.add_field(field_name.clone(), FieldType::Uuid); + mtt.create_document(docdef); + let mut add = Addition::new(doc_name.clone()); + add.add_field(Name::english("missing"), "something"); + let mut expected = MTTError::new(ErrorID::FieldTypeExpected(FieldType::Uuid)); + expected.add_parent(ErrorID::Field(field_name.clone().into())); + expected.add_parent(ErrorID::Document(doc_name.clone().into())); + let result = mtt.records(add).unwrap_err(); + assert_eq!(result.to_string(), expected.to_string()); }