diff --git a/src/message.rs b/src/message.rs index 34a65cc..286f63d 100644 --- a/src/message.rs +++ b/src/message.rs @@ -23,7 +23,7 @@ enum MTTError { DocumentFieldNotFound(String), DocumentFieldWrongDataType(FieldType, FieldType), DocumentNotFound(String), - FieldDuplicate, + FieldDuplicate(String, Field), } #[derive(Clone, Debug, Eq, Hash, PartialEq)] @@ -1128,6 +1128,12 @@ impl FieldSetting { } } + fn remove_unique_value(&mut self, field: &Field) { + if self.use_unique { + self.unique.remove(field); + } + } + fn check(&self, value: Option) -> Result { match value { Some(data) => { @@ -1140,7 +1146,7 @@ impl FieldSetting { } if self.use_unique { if self.unique.get(&data).is_some() { - return Err(MTTError::FieldDuplicate); + return Err(MTTError::FieldDuplicate("".to_string(), data.clone())); } } Ok(data.clone()) @@ -1228,10 +1234,13 @@ mod fieldsettings { let field: Field = Uuid::new_v4().into(); fset.set_unique(); fset.use_unique_value(field.clone()); - match fset.check(Some(field)) { + match fset.check(Some(field.clone())) { Ok(data) => unreachable!("got {:?}: should have been error", data), Err(err) => match err { - MTTError::FieldDuplicate => {} + MTTError::FieldDuplicate(key, result) => { + assert_eq!(key, ""); + assert_eq!(result, field); + } _ => unreachable!("got {:?}: should be a duplicate field", err), }, } @@ -1338,6 +1347,14 @@ impl DocDef { } } + fn check(&self, field_name: &str, value: Option) -> Result { + let setting = match self.get_field(field_name) { + Ok(data) => data, + Err(err) => return Err(err), + }; + setting.check(value) + } + fn set_default(&mut self, field_name: &str, value: Option) -> Result<(), MTTError> { let setting = match self.get_field_mut(field_name) { Ok(data) => data, @@ -1370,6 +1387,15 @@ impl DocDef { Ok(()) } + fn remove_unique_value(&mut self, field_name: &str, field: &Field) -> Result<(), MTTError> { + let setting = match self.get_field_mut(field_name) { + Ok(data) => data, + Err(err) => return Err(err), + }; + setting.remove_unique_value(field); + Ok(()) + } + fn iter(&self) -> impl Iterator { self.fields.iter() } @@ -1836,18 +1862,21 @@ impl DocumentFile { self.docs.iter() } + fn add_field_to_error(key: String, err: MTTError) -> MTTError { + match err { + MTTError::DocumentFieldMissing(_) => MTTError::DocumentFieldMissing(key), + MTTError::FieldDuplicate(_, field) => MTTError::FieldDuplicate(key, field.clone()), + _ => err.clone(), + } + } + fn add_document(&mut self, addition: &Addition) -> MsgAction { let mut holder = Document::new(); let doc = addition.get_document(); for (key, value) in doc.iter() { - match self.docdef.get_field_mut(&key) { - Ok(field_info) => match field_info.check(Some(value.clone())) { - Ok(data) => { - holder.add_field(key.clone(), value.clone()); - } - Err(err) => return err.into(), - }, - Err(err) => return err.into(), + match self.docdef.check(key, Some(value.clone())) { + Ok(data) => holder.add_field(key.clone(), value.clone()), + Err(err) => return Self::add_field_to_error(key.to_string(), err).into(), } } for (key, value) in self.docdef.iter() { @@ -1855,15 +1884,7 @@ impl DocumentFile { Some(_) => {} None => match value.check(None) { Ok(data) => holder.add_field(key.clone(), data.clone()), - Err(err) => { - let error = match err { - MTTError::DocumentFieldMissing(_) => { - MTTError::DocumentFieldMissing(key.clone()) - } - _ => err.clone(), - }; - return error.into(); - } + Err(err) => return Self::add_field_to_error(key.to_string(), err).into(), }, } } @@ -1883,12 +1904,15 @@ impl DocumentFile { fn run_query(&self, query: &Query) -> Result, MTTError> { let mut reply = Reply::new(); for specifier in query.iter() { - match self.docdef.get_field(&specifier.field_name) { - Ok(spec) => match spec.check(Some(specifier.value.clone())) { - Ok(_) => {} - Err(err) => return Err(err), + match self + .docdef + .check(&specifier.field_name, Some(specifier.value.clone())) + { + Ok(_) => {} + Err(err) => match err { + MTTError::FieldDuplicate(_, _) => {} + _ => return Err(err), }, - Err(err) => return Err(err), } } let mut result = Vec::new(); @@ -1929,11 +1953,12 @@ impl DocumentFile { for oid in oids.iter() { let doc = self.docs.get_mut(oid).unwrap(); for (key, value) in update.get_values().iter() { - match self.docdef.get_field(key) { - Ok(fset) => match fset.check(Some(value.clone())) { - Ok(field) => doc.add_field(key.clone(), field.clone()), - Err(err) => return err.into(), - }, + match self.docdef.check(key, Some(value.clone())) { + Ok(field) => { + self.docdef + .remove_unique_value(key, doc.get_field(key).unwrap()); + doc.add_field(key.clone(), field.clone()); + } Err(err) => return err.into(), } } @@ -2751,7 +2776,11 @@ mod document_files { let action = result.get_action(); match action { MsgAction::Error(err) => match err { - MTTError::FieldDuplicate => {} + MTTError::FieldDuplicate(key, field) => { + let expected: Field = field0.into(); + assert_eq!(key, "field0"); + assert_eq!(field, &expected); + } _ => unreachable!("got {:?}: should have gotten an missing field", err), }, _ => unreachable!("got {:?}: should have gotten an error", action), @@ -2782,6 +2811,66 @@ mod document_files { _ => unreachable!("got {:?}: should have gotten a reply", action), } } + + #[test] + fn updating_unique_removes_old_entry() { + let (mut docdef, doc_name) = create_docdef([FieldType::Uuid].to_vec()); + docdef.set_unique("field0"); + let (queue, rx) = test_doc(doc_name.as_str(), docdef, standard_routes()); + let old = Uuid::new_v4(); + let mut new = Uuid::new_v4(); + while old == new { + new = Uuid::new_v4(); + } + let fold: Field = old.into(); + let fnew: Field = new.into(); + let mut addition = Addition::new(); + addition.add_field("field0".to_string(), old.clone()); + let msg = Message::new(doc_name.clone(), addition.clone()); + queue.send(msg).unwrap(); + rx.recv_timeout(TIMEOUT).unwrap(); + let mut update = Update::new(); + let query = update.get_query_mut(); + query.add_specifier("field0".to_string(), Operand::Equal, old.clone()); + let values = update.get_values_mut(); + values.add_field("field0".to_string(), new.clone()); + let msg = Message::new(doc_name.clone(), update); + queue.send(msg).unwrap(); + let result = rx.recv_timeout(TIMEOUT).unwrap(); + let action = result.get_action(); + match action { + MsgAction::Reply(data) => { + assert_eq!(data.len(), 1); + for doc in data.iter() { + assert_eq!( + doc.get_field("field0").unwrap(), + &fnew, + "got {:?} as a reply", + data + ); + } + } + _ => unreachable!("got {:?}: should have gotten a reply", action), + } + let msg = Message::new(doc_name.clone(), addition.clone()); + queue.send(msg).unwrap(); + let result = rx.recv_timeout(TIMEOUT).unwrap(); + let action = result.get_action(); + match action { + MsgAction::Reply(data) => { + assert_eq!(data.len(), 1); + for doc in data.iter() { + assert_eq!( + doc.get_field("field0").unwrap(), + &fold, + "got {:?} as a reply", + data + ); + } + } + _ => unreachable!("got {:?}: should have gotten a reply", action), + } + } } #[cfg(test)]