diff --git a/src/message.rs b/src/message.rs index e1dc5ea..fb348b8 100644 --- a/src/message.rs +++ b/src/message.rs @@ -46,6 +46,7 @@ enum Action { Create, Delete, Error, + On, Query, Records, Register, @@ -61,6 +62,7 @@ impl From for Action { MsgAction::Create(_) => Action::Create, MsgAction::Delete(_) => Action::Delete, MsgAction::Error(_) => Action::Error, + MsgAction::On(_) => Action::On, MsgAction::Query(_) => Action::Query, MsgAction::Records(_) => Action::Records, MsgAction::Register(_) => Action::Register, @@ -125,6 +127,7 @@ enum MsgAction { // Alter // Remove Error(MTTError), + On(On), Query(Query), Records(RecordIter), Register(Register), @@ -2348,6 +2351,10 @@ impl Addition { fn get_document(&self) -> Document { self.data.clone() } + + fn iter(&self) -> impl Iterator { + self.data.iter() + } } #[cfg(test)] @@ -2404,6 +2411,42 @@ mod additions { } } +#[derive(Clone, Debug)] +enum OnType { + Query, + Update, +} + +#[derive(Clone, Debug)] +struct On; + +impl On { + fn new(on_type: OnType) -> Self { + Self {} + } + + fn get_type(&self) -> &OnType { + &OnType::Query + } +} + +#[cfg(test)] +mod ons { + use super::*; + + #[test] + #[ignore] + fn can_create_on_action() { + let value = OnType::Update; + let on = On::new(value.clone()); + let on_type = on.get_type(); + match on_type { + OnType::Update => {}, + _ => unreachable!("got {:?}, should have been update", on_type), + } + } +} + #[derive(Clone, Debug)] enum IndexType { Index, @@ -2632,7 +2675,6 @@ mod docdefs { #[derive(Clone, Debug)] enum Operand { Add, - //Assign, Equal, } @@ -2904,20 +2946,6 @@ impl Calculation { output } - fn push_value( - &mut self, - base: FieldType, - ftype: FieldType, - data: CalcValue, - ) -> Result<(), MTTError> { - if base == ftype { - self.values.push(data); - } else { - return Err(MTTError::DocumentFieldWrongDataType(base, ftype)); - } - Ok(()) - } - fn get_type(&self) -> FieldType { if self.values.is_empty() { FieldType::None @@ -2935,23 +2963,23 @@ impl Calculation { self.values.push(holder); return Ok(()); } - let ftype = holder.get_type(); let mut base = self.get_type(); match self.operation { Operand::Add => { - if base == FieldType::DateTime { - base = FieldType::Duration; - } - match self.push_value(base, ftype, holder) { - Ok(_) => Ok(()), - Err(err) => Err(err), + match base { + FieldType::DateTime => base = FieldType::Duration, + _ => {}, } } - _ => match self.push_value(base, ftype, holder) { - Ok(_) => Ok(()), - Err(err) => Err(err), - }, + _ => {}, } + let ftype = holder.get_type(); + if base == ftype { + self.values.push(holder); + } else { + return Err(MTTError::DocumentFieldWrongDataType(base, ftype)); + } + Ok(()) } fn validate_value(&self, value: CV) -> Result<(), MTTError> @@ -3667,9 +3695,15 @@ impl Document { output } + fn iter(&self) -> impl Iterator { + self.data.iter() + } + + /* fn iter(&self) -> DocIter { DocIter::new(self) } + */ fn is_empty(&self) -> bool { self.data.is_empty() @@ -3797,6 +3831,22 @@ impl Oid { } } +#[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); + } + } +} + #[derive(Debug)] struct Index { data: HashMap>, @@ -3875,8 +3925,13 @@ impl Index { fn pull(&self, calc: &Calculation) -> Result, MTTError> { let mut output = HashSet::new(); for (key, value) in self.data.iter() { - if calc.calculate(key) == true.into() { - output = output.union(&value).cloned().collect(); + match calc.calculate(key) { + Field::Boolean(data) => { + if data { + output = output.union(&value).cloned().collect(); + } + } + _ => return Err(MTTError::FieldInvalidType), } } Ok(output) @@ -4206,7 +4261,7 @@ impl DocumentFile { &self.docdef } - fn validate(&self, field_name: NT, value: &Field) -> Result<(Uuid, Field), MTTError> + fn validate(&self, field_name: NT, value: &Field) -> Result where NT: Into, { @@ -4222,7 +4277,7 @@ impl DocumentFile { Ok(_) => {} Err(err) => return Err(err), } - Ok((field_id, output)) + Ok(output) } fn add_field_to_error(key: String, err: MTTError) -> MTTError { @@ -4250,6 +4305,53 @@ impl DocumentFile { fn add_document(&mut self, addition: &Addition) -> MsgAction { let mut holder = InternalRecord::new(); + for (name_id, value) in addition.iter() { + let field_id = match self.docdef.get_field_id(name_id) { + Ok(id) => id, + Err(err) => return MsgAction::Error(err), + }; + holder.insert(field_id.clone(), value.get(&Field::None)); + } + for field_id in self.docdef.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) => return MsgAction::Error(err), + }; + holder.insert(field_id.clone(), corrected.clone()); + } + let mut records = RecordIter::with_names(self.docdef.get_field_names().clone()); + if !holder.is_empty() { + let mut oid = Oid::new(); + while self.docs.contains_key(&oid) { + oid = Oid::new(); + } + for (field_id, oids) in self.indexes.iter_mut() { + let value = holder.get(field_id).unwrap(); + oids.internal_add(value, oid.clone()); + } + self.docs.insert(oid.clone(), holder.clone()); + records.insert(holder); + } + records.into() + + + + + + + + /* + for (field_id, value) in addition.iter() { + let id = match self.docdef.get_field_id(field_id) { + Ok(fid) => fid, + Err(err) => return MsgAction::Error(err), + }; + } + let doc = addition.get_document(); for (field, value) in doc.iter() { match self.validate(field, &value) { @@ -4283,6 +4385,7 @@ impl DocumentFile { records.insert(holder); } records.into() + */ } fn delete(&mut self, delete: &Delete) -> MsgAction { @@ -4356,6 +4459,54 @@ impl DocumentFile { } fn update(&mut self, update: &Update) -> MsgAction { + let oids = match self.run_query(update.get_query()) { + Ok(result) => result, + Err(err) => return err.into(), + }; + 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, + Err(err) => return err.into(), + }; + changes.insert(field_id, value); + } + let mut indexes = self.docdef.create_indexes(); + let mut old: HashMap = HashMap::new(); + let mut changed: HashMap = HashMap::new(); + for oid in oids.iter() { + let mut holder = self.docs.get(oid).unwrap().clone(); + old.insert(oid.clone(), holder.clone()); + for (field_id, value) in changes.iter() { + let field = value.get(holder.get(field_id).unwrap()); + let correction = match self.validate(field_id, &field) { + Ok(data) => data, + Err(err) => return err.into(), + }; + holder.insert(field_id.clone(), field); + match indexes.add_to_index(&field_id, correction, oid.clone()) { + Ok(_) => {} + Err(err) => return err.into(), + } + } + changed.insert(oid.clone(), holder); + } + let mut output = RecordIter::with_names(self.docdef.get_field_names().clone()); + for (oid, record) in changed.iter() { + let original = old.get(oid).unwrap(); + let new_rec = changed.get(oid).unwrap(); + for (field_id, index) in self.indexes.iter_mut() { + index.remove(original.get(field_id).unwrap(), oid); + index.add(new_rec.get(field_id).unwrap().clone(), oid.clone()); + } + self.docs.insert(oid.clone(), new_rec.clone()); + output.insert(new_rec.clone()); + } + output.into() + + + + /* let mut changes: HashMap = HashMap::new(); for (key, value) in update.get_values().iter() { let (id, field) = match self.validate(key, &value) { @@ -4398,6 +4549,7 @@ impl DocumentFile { output.insert(record.clone()); } output.into() + */ } } @@ -5030,7 +5182,6 @@ mod document_files { } #[test] - #[ignore] fn errors_on_bad_field_type_with_index() { let mut doc = TestDocument::new([FieldType::Uuid].to_vec()); doc.get_docdef_mut() @@ -5046,11 +5197,8 @@ mod document_files { let action = result.get_action(); match action { MsgAction::Error(data) => match data { - MTTError::DocumentFieldWrongDataType(expected, got) => { - assert_eq!(got, &FieldType::Uuid); - assert_eq!(expected, &FieldType::StaticString); - } - _ => unreachable!("got {:?}: should been field not found", data), + MTTError::FieldInvalidType => {}, + _ => unreachable!("got {:?}: should been invalid field type", data), }, _ => unreachable!("got {:?}: should have been a error", action), } @@ -5142,7 +5290,6 @@ mod document_files { } #[test] - #[ignore] fn empty_update_query_results_in_zero_changes() { let count = 5; let mut ids: HashSet = HashSet::new(); @@ -5173,7 +5320,6 @@ mod document_files { } #[test] - #[ignore] fn changes_information_requested() { let mut doc = TestDocument::new([FieldType::Uuid, FieldType::StaticString].to_vec()); doc.start(); @@ -5184,7 +5330,8 @@ mod document_files { doc.populate([id.into(), old.into()].to_vec()); let mut update = Update::new(); let mut calc = Calculation::new(Operand::Equal); - calc.add_value(id.clone()); + calc.add_value(CalcValue::Existing(FieldType::Uuid)).unwrap(); + calc.add_value(id.clone()).unwrap(); update.get_query_mut().add(Name::english("field0"), calc); update .get_values_mut() @@ -5196,7 +5343,7 @@ mod document_files { let action = result.get_action(); match action { MsgAction::Records(docs) => { - assert_eq!(docs.len(), 1, "should have one entry"); + assert_eq!(docs.len(), 1, "for {:?}, should have one entry", msg); for doc in docs.clone() { assert_eq!(doc.get(Name::english("field0")).unwrap(), id.into()); assert_eq!(doc.get(Name::english("field1")).unwrap(), new.into()); @@ -5210,7 +5357,6 @@ mod document_files { } #[test] - #[ignore] fn changes_only_the_queried() { let mut doc = TestDocument::new([FieldType::Integer, FieldType::StaticString].to_vec()); doc.start(); @@ -5224,7 +5370,8 @@ mod document_files { } let mut update = Update::new(); let mut calc = Calculation::new(Operand::Equal); - calc.add_value(picked.clone()); + calc.add_value(picked.clone()).unwrap(); + calc.add_value(CalcValue::Existing(FieldType::Integer)).unwrap(); update.get_query_mut().add(Name::english("field0"), calc); update .get_values_mut() @@ -5265,7 +5412,6 @@ mod document_files { } #[test] - #[ignore] fn can_handle_multiple_updates() { let mut doc = TestDocument::new([FieldType::Integer, FieldType::StaticString].to_vec()); doc.start(); @@ -5279,7 +5425,8 @@ mod document_files { } let mut update = Update::new(); let mut calc = Calculation::new(Operand::Equal); - calc.add_value(picked.clone()); + calc.add_value(picked.clone()).unwrap(); + calc.add_value(CalcValue::Existing(FieldType::Integer)).unwrap(); update.get_query_mut().add(Name::english("field0"), calc); update .get_values_mut() @@ -5340,6 +5487,7 @@ mod document_files { let mut update = Update::new(); let mut calc = Calculation::new(Operand::Equal); calc.add_value(id.clone()); + calc.add_value(CalcValue::Existing(FieldType::Uuid)); update.get_query_mut().add(Name::english("field0"), calc); update .get_values_mut() @@ -5360,7 +5508,6 @@ mod document_files { } #[test] - #[ignore] fn does_update_maintain_unique_fields() { let mut test_doc = TestDocument::new([FieldType::Integer].to_vec()); test_doc @@ -5443,7 +5590,6 @@ mod document_files { } #[test] - #[ignore] fn updating_unique_updates_index_entries() { let fname = Name::english("field0"); let mut doc = TestDocument::new([FieldType::StaticString].to_vec()); @@ -5457,6 +5603,7 @@ mod document_files { let mut update = Update::new(); let mut calc = Calculation::new(Operand::Equal); calc.add_value(old); + calc.add_value(CalcValue::Existing(FieldType::StaticString)); update.get_query_mut().add(fname.clone(), calc); update.get_values_mut().add_field(fname.clone(), new); doc.send(update).unwrap(); @@ -5490,7 +5637,6 @@ mod document_files { } #[test] - #[ignore] fn update_does_not_override_unique_index() { let f0name = Name::english("field0"); let f1name = Name::english("field1"); @@ -5511,7 +5657,8 @@ mod document_files { } let mut update = Update::new(); let mut calc = Calculation::new(Operand::Equal); - calc.add_value(data); + calc.add_value(data).unwrap(); + calc.add_value(CalcValue::Existing(FieldType::StaticString)).unwrap(); update.get_query_mut().add(&f1name, calc); update.get_values_mut().add_field(&f0name, holder.clone()); doc.send(update).unwrap(); @@ -5577,7 +5724,6 @@ mod document_files { } #[test] - #[ignore] fn can_delete() { let fname = Name::english("field0"); let mut doc = TestDocument::new([FieldType::Integer].to_vec()); @@ -5585,6 +5731,7 @@ mod document_files { doc.populate([1.into()].to_vec()); let mut calc = Calculation::new(Operand::Equal); calc.add_value(1); + calc.add_value(CalcValue::Existing(FieldType::Integer)); let mut query = Query::new(); query.add(&fname, calc); let mut delete = Delete::new();