diff --git a/src/message.rs b/src/message.rs index bc3c0b4..c17efa0 100644 --- a/src/message.rs +++ b/src/message.rs @@ -3908,16 +3908,19 @@ impl Index { output } - fn pull(&self, calc: &Calculation) -> HashSet { + fn pull(&self, calc: &Calculation) -> Result, MTTError> { let mut output = HashSet::new(); for (key, value) in self.data.iter() { let mut op = calc.clone(); - op.add_value(key.clone()); + match op.add_value(key.clone()) { + Ok(_) => {}, + Err(err) => return Err(err), + } if op.calculate() == true.into() { output = output.union(&value).cloned().collect(); } } - output + Ok(output) } fn remove(&mut self, field: &Field, oid: &Oid) { @@ -3964,9 +3967,7 @@ impl Indexes { self.data.get(field_id).unwrap() } - fn pull(&self, field_id: &Uuid, calc: &Calculation) -> HashSet { - println!("{:?}", field_id); - println!("{:?}", self.data); + fn pull(&self, field_id: &Uuid, calc: &Calculation) -> Result, MTTError> { self.data.get(field_id).unwrap().pull(calc) } @@ -4343,107 +4344,10 @@ impl DocumentFile { } let mut oids: HashSet = self.docs.keys().cloned().collect(); for (field_id, calculation) in indexed.iter() { - let holder = self.indexes.pull(field_id, calculation); - oids = oids.intersection(&holder).cloned().collect(); - } - for (field_id, calculation) in unindexed.iter() { - for oid in oids.clone().iter() { - let doc = self.docs.get(oid).unwrap(); - let mut calc = calculation.clone(); - calc.add_value(doc.get(field_id).unwrap().clone()); - if calc.calculate() == false.into() { - oids.remove(oid); - } - } - } - Ok(oids) - - /* - let query_ids = query.field_ids(); - let doc_ids = self.docdef.field_ids(); - let index_ids = self.indexes.index_ids(); - if !doc_ids.is_superset(&query_ids) { - let missed = query_ids.difference(&doc_ids).last().unwrap(); - return Err(MTTError::DocumentFieldNotFound(missed.to_string())); - } - let used_indexed = index_ids - .intersection(&query_ids) - .cloned() - .collect::>(); - let used_unindexed = query_ids - .difference(&index_ids) - .cloned() - .collect::>(); - let mut oids = HashSet::new(); - if used_indexed.is_empty() { - 'docs: for (oid, doc) in self.docs.iter() { - for query_id in query_ids.iter() { - let doc_data = doc.get_field(query_id).unwrap(); - let mut operation = query.get(query_id).unwrap(); - match operation.add_value(doc_data.clone()) { - Ok(_) => {} - Err(err) => match err { - MTTError::DocumentFieldWrongDataType(got, expected) => { - return Err(MTTError::DocumentFieldWrongDataType(expected, got)) - } - _ => return Err(err), - }, - } - if operation.calculate() == false.into() { - continue 'docs; - } - } - oids.insert(oid.clone()); - } - } else { - let mut first_time = true; - for field_id in used_indexed.iter() { - let op = query.get(field_id).unwrap(); - let holder = self.indexes.pull(field_id, &op); - if first_time { - oids = holder; - } else { - oids = oids.intersection(&holder).cloned().collect(); - } - first_time = false; - } - for field_id in used_unindexed.iter() { - let mut holder: HashSet = HashSet::new(); - for oid in oids.iter() { - let doc = self.docs.get(oid).unwrap(); - let mut op = query.get(field_id).unwrap().clone(); - op.add_value(doc.get_field(field_id).unwrap()); - if op.calculate() == true.into() { - holder.insert(oid.clone()); - } - } - oids = oids.intersection(&holder).cloned().collect(); - } - } - Ok(oids) - */ - } - - fn query(&self, query: &Query) -> MsgAction { - let mut records = RecordIter::with_names(self.docdef.get_field_names().clone()); - let indexed_ids = self.indexes.index_ids(); - 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, - Err(err) => return err.into(), + let holder = match self.indexes.pull(field_id, calculation) { + Ok(data) => data, + Err(err) => return Err(err), }; - if indexed_ids.contains(&id) { - indexed.insert(id, data.clone()); - } else { - unindexed.insert(id, data.clone()); - } - } - let mut oids: HashSet = self.docs.keys().cloned().collect(); - for (field_id, calculation) in indexed.iter() { - let holder = self.indexes.pull(field_id, calculation); - println!("{:?}", holder); oids = oids.intersection(&holder).cloned().collect(); } for (field_id, calculation) in unindexed.iter() { @@ -4452,13 +4356,22 @@ impl DocumentFile { let mut calc = calculation.clone(); match calc.add_value(doc.get(field_id).unwrap().clone()) { Ok(_) => {}, - Err(err) => return err.into(), + Err(err) => return Err(err), } if calc.calculate() == false.into() { oids.remove(oid); } } } + Ok(oids) + } + + fn query(&self, query: &Query) -> MsgAction { + let oids = match self.run_query(query) { + Ok(data) => data, + Err(err) => return err.into(), + }; + let mut records = RecordIter::with_names(self.docdef.get_field_names().clone()); for oid in oids.iter() { records.insert(self.docs.get(oid).unwrap().clone()); } @@ -4466,48 +4379,27 @@ impl DocumentFile { } fn update(&mut self, update: &Update) -> MsgAction { - /* + let mut changes: HashMap = HashMap::new(); + for (key, value) in update.get_values().iter() { + let (id, field) = match self.validate(key, Some(value.clone())) { + Ok(data) => data, + Err(err) => return err.into(), + }; + changes.insert(id, field); + } let oids = match self.run_query(update.get_query()) { Ok(result) => result, Err(err) => return err.into(), }; - let mut holder: HashMap = HashMap::new(); + let mut output = RecordIter::with_names(self.docdef.get_field_names().clone()); for oid in oids.iter() { - let doc = self.docs.get(oid).unwrap(); - let old_new = [doc.clone(), doc.clone()]; - holder.insert(oid.clone(), old_new); - } - let mut index_holder = self.docdef.create_indexes(); - for (oid, docs) in holder.iter_mut() { - let mut updated = Document::new(); - for (key, value) in update.get_values().iter() { - match self.validate(&key, Some(value.clone())) { - Ok(field) => { - let id = self.docdef.get_field_id(&key).unwrap(); - match index_holder.validate(&id, &field) { - Ok(_) => { - index_holder.add_to_index(&id, field.clone(), oid.clone()); - docs[1].add_field(key.clone(), field.clone()); - } - Err(err) => return Self::add_field_to_error(key.to_string(), err).into(), - } - } - Err(err) => return err.into(), - } + let rec = self.docs.get_mut(oid).unwrap(); + for (field_id, value) in changes.iter() { + rec.insert(field_id.clone(), value.clone()); } + output.insert(rec.clone()); } - let mut reply = Reply::new(); - for (oid, docs) in holder.iter() { - self.docs.insert(oid.clone(), docs[1].clone()); - reply.add(docs[1].clone()); - for (key, value) in docs[0].iter() { - self.remove_from_index(&key, &value, oid); - self.add_to_index(&key, docs[1].get_field(&key).unwrap().clone(), oid.clone()); - } - } - reply.into() - */ - Reply::new().into() + output.into() } } @@ -5094,25 +4986,55 @@ mod document_files { } } - /* + #[test] + fn errors_on_bad_field_type_with_index() { + let mut doc = TestDocument::new([FieldType::Uuid].to_vec()); + doc.get_docdef_mut().add_index(&Name::english("field0"), IndexType::Index); + doc.start(); + doc.populate([Uuid::nil().into()].to_vec()); + let mut calc = Calculation::new(Operand::Equal); + calc.add_value("notUUID"); + let mut query = Query::new(); + query.add(Name::english("field0"), calc); + doc.send(query).unwrap(); + let result = doc.get_receiver().recv_timeout(TIMEOUT).unwrap(); + 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), + }, + _ => unreachable!("got {:?}: should have been a error", action), + } + } + #[test] fn can_use_default_values() { - let (mut docdef, doc_name) = create_docdef([FieldType::StaticString].to_vec()); + let doc_name = Name::english("default"); + let mut docdef = DocDef::new(doc_name.clone()); + let field_name = Name::english("holder"); + docdef.add_field(field_name.clone(), FieldType::StaticString); let mut calc = Calculation::new(Operand::Assign); calc.add_value(FieldType::StaticString); - docdef.set_default("field0", calc); - let (queue, rx) = test_doc(doc_name.as_str(), docdef, standard_routes()); + docdef.set_default(&field_name, calc); + let mut test_doc: TestDocument = docdef.into(); + test_doc.start(); + let queue = test_doc.get_queue(); + let rx = test_doc.get_receiver(); let new_doc = Addition::new(); let msg = Message::new(doc_name, new_doc); queue.send(msg).unwrap(); let result = rx.recv_timeout(TIMEOUT).unwrap(); let action = result.get_action(); match action { - MsgAction::Reply(docs) => { + MsgAction::Records(docs) => { assert_eq!(docs.len(), 1); - for doc in docs.iter() { + for doc in docs.clone() { let expected: Field = "".into(); - assert_eq!(doc.get_field("field0").unwrap(), expected); + assert_eq!(doc.get(&field_name).unwrap(), expected); } } _ => unreachable!("got {:?}: should have gotten a reply", action), @@ -5121,23 +5043,28 @@ mod document_files { #[test] fn can_a_default_value_be_set() { - let (mut docdef, doc_name) = create_docdef([FieldType::Uuid].to_vec()); - let input = Uuid::nil(); + let doc_name = Name::english("assigned"); + let mut docdef = DocDef::new(doc_name.clone()); + let field_name = Name::english("id"); + docdef.add_field(field_name.clone(), FieldType::Uuid); let mut calc = Calculation::new(Operand::Assign); - calc.add_value(input.clone()); - docdef.set_default("field0", calc); - let (queue, rx) = test_doc(doc_name.as_str(), docdef, standard_routes()); + calc.add_value(Uuid::nil()); + docdef.set_default(&field_name, calc); + let mut test_doc: TestDocument = docdef.into(); + test_doc.start(); + let queue = test_doc.get_queue(); + let rx = test_doc.get_receiver(); let new_doc = Addition::new(); let msg = Message::new(doc_name, new_doc); queue.send(msg).unwrap(); let result = rx.recv_timeout(TIMEOUT).unwrap(); let action = result.get_action(); match action { - MsgAction::Reply(docs) => { + MsgAction::Records(docs) => { assert_eq!(docs.len(), 1); - let expected: Field = input.into(); - for doc in docs.iter() { - assert_eq!(doc.get_field("field0").unwrap(), expected); + for doc in docs.clone() { + let expected: Field = Uuid::nil().into(); + assert_eq!(doc.get(&field_name).unwrap(), expected); } } _ => unreachable!("got {:?}: should have gotten a reply", action), @@ -5146,23 +5073,29 @@ mod document_files { #[test] fn can_default_values_be_overridden() { - let (mut docdef, doc_name) = create_docdef([FieldType::Uuid].to_vec()); + let doc_name = Name::english("assigned"); + let mut docdef = DocDef::new(doc_name.clone()); + let field_name = Name::english("id"); + docdef.add_field(field_name.clone(), FieldType::Uuid); let mut calc = Calculation::new(Operand::Assign); calc.add_value(FieldType::Uuid); - docdef.set_default("field0", calc); - let (queue, rx) = test_doc(doc_name.as_str(), docdef, standard_routes()); + docdef.set_default(&field_name, calc); + let mut test_doc: TestDocument = docdef.into(); + test_doc.start(); + let queue = test_doc.get_queue(); + let rx = test_doc.get_receiver(); let mut new_doc = Addition::new(); - new_doc.add_field("field0".to_string(), Uuid::nil()); + new_doc.add_field(&field_name, Uuid::nil()); let msg = Message::new(doc_name, new_doc); queue.send(msg).unwrap(); let result = rx.recv_timeout(TIMEOUT).unwrap(); let action = result.get_action(); match action { - MsgAction::Reply(docs) => { + MsgAction::Records(docs) => { assert_eq!(docs.len(), 1); - let expected: Field = Uuid::nil().into(); - for doc in docs.iter() { - assert_eq!(doc.get_field("field0").unwrap(), expected); + for doc in docs.clone() { + let expected: Field = Uuid::nil().into(); + assert_eq!(doc.get(&field_name).unwrap(), expected); } } _ => unreachable!("got {:?}: should have gotten a reply", action), @@ -5186,86 +5119,56 @@ mod document_files { let mut update = Update::new(); let mut calc = Calculation::new(Operand::Equal); calc.add_value(id); - update.get_query_mut().add("field0".to_string(), calc); + update.get_query_mut().add(Name::english("field0"), calc); update .get_values_mut() - .add_field("field0".to_string(), Uuid::nil()); + .add_field(Name::english("field0"), Uuid::nil()); doc.send(update).unwrap(); let result = doc.get_receiver().recv_timeout(TIMEOUT).unwrap(); let action = result.get_action(); match action { - MsgAction::Reply(docs) => assert_eq!(docs.len(), 0), + MsgAction::Records(docs) => assert_eq!(docs.len(), 0), _ => unreachable!("got {:?}: should have gotten a reply", action), } } - #[test] - fn only_responses_to_its_update_request() { - let mut doc = TestDocument::new([FieldType::Integer].to_vec()); - doc.start(); - let alt_doc_name = "alternate"; - let (tx, _) = channel(); - let mut queue = doc.get_queue(); - queue - .register(tx, alt_doc_name.to_string(), Vec::new()) - .unwrap(); - let update = Update::new(); - let msg = Message::new(alt_doc_name, update); - queue.send(msg).unwrap(); - match doc.get_receiver().recv_timeout(TIMEOUT) { - Ok(msg) => unreachable!("should not receive: {:?}", msg), - Err(err) => match err { - RecvTimeoutError::Timeout => {} - _ => unreachable!("should have timed out"), - }, - } - } - #[test] fn changes_information_requested() { let mut doc = TestDocument::new([FieldType::Uuid, FieldType::StaticString].to_vec()); doc.start(); - let id = Uuid::new_v4(); + let doc_name = doc.get_docdef().get_document_name().clone(); let old = "old"; let new = "new"; + let id = Uuid::new_v4(); 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()); update .get_query_mut() - .add("field0".to_string(), calc.clone()); - update.get_values_mut().add_field("field1".to_string(), new); - doc.send(update).unwrap(); - let mut results: HashMap = HashMap::new(); - results.insert( - "update".to_string(), - doc.get_receiver().recv_timeout(TIMEOUT).unwrap(), - ); - let mut query = Query::new(); - query.add("field0".to_string(), calc.clone()); - doc.send(query).unwrap(); - results.insert( - "query".to_string(), - doc.get_receiver().recv_timeout(TIMEOUT).unwrap(), - ); - let expected_id: Field = id.into(); - let output: Field = new.into(); - for (key, result) in results.iter() { + .add(Name::english("field0"), calc); + update.get_values_mut().add_field(Name::english("field1"), new); + let mut testing = |msg: Message| { + doc.get_queue().send(msg.clone()).unwrap(); + let result = doc.get_receiver().recv_timeout(TIMEOUT).unwrap(); + assert_eq!(result.get_message_id(), msg.get_message_id()); let action = result.get_action(); match action { - MsgAction::Reply(docs) => { - assert_eq!(docs.len(), 1, "{}", key); - for doc in docs.iter() { - assert_eq!(doc.get_field("field0").unwrap(), expected_id, "{}", key); - assert_eq!(doc.get_field("field1").unwrap(), output, "{}", key); + MsgAction::Records(docs) => { + assert_eq!(docs.len(), 1, "should have one entry"); + 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()); } } _ => unreachable!("got {:?}: should have gotten a reply", action), } - } + }; + testing(Message::new(doc_name.clone(), update)); + testing(Message::new(doc_name.clone(), Query::new())); } + /* #[test] fn changes_only_the_queried() { let mut doc = TestDocument::new([FieldType::Uuid, FieldType::StaticString].to_vec());