diff --git a/src/message.rs b/src/message.rs index fceadf6..0abc4e4 100644 --- a/src/message.rs +++ b/src/message.rs @@ -959,7 +959,16 @@ enum FieldType { Uuid, } -#[derive(Clone, Debug)] +impl From<&Field> for FieldType { + fn from(value: &Field) -> Self { + match value { + Field::StaticString(_) => Self::StaticString, + Field::Uuid(_) => Self::Uuid, + } + } +} + +#[derive(Clone, Debug, PartialEq)] enum Field { StaticString(String), Uuid(Uuid), @@ -967,10 +976,7 @@ enum Field { impl Field { fn get_type(&self) -> FieldType { - match self { - Self::StaticString(_) => FieldType::StaticString, - Self::Uuid(_) => FieldType::Uuid, - } + self.into() } } @@ -1209,11 +1215,65 @@ mod docdefs { } #[derive(Clone, Debug)] -struct Query; +enum Operand { + Equal, +} + +#[derive(Clone, Debug)] +struct Specifier { + field_name: String, + operation: Operand, + value: Field, +} + +impl Specifier { + fn new(name: String, op: Operand, value: F) -> Self + where + F: Into, + { + Self { + field_name: name, + operation: op, + value: value.into(), + } + } +} + +#[derive(Clone, Debug)] +struct Query { + specifiers: Vec, +} impl Query { fn new() -> Self { - Self {} + Self { + specifiers: Vec::new(), + } + } + + fn add_specifier(&mut self, name: String, op: Operand, value: F) + where + F: Into, + { + let spec = Specifier::new(name, op, value); + self.specifiers.push(spec); + } + + fn run(&self, docs: &DocumentFile) -> Reply { + let mut reply = Reply::new(); + for doc in docs.get_documents() { + let mut output = true; + for specifier in self.specifiers.iter() { + let value = doc.get_field(&specifier.field_name).unwrap(); + if value != &specifier.value { + output = false; + } + } + if output { + reply.add(doc.clone()); + } + } + reply } } @@ -1234,14 +1294,9 @@ impl Reply { fn len(&self) -> usize { self.data.len() } -} -impl IntoIterator for Reply { - type Item = Document; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.data.into_iter() + fn iter(&self) -> impl Iterator { + self.data.iter() } } @@ -1275,7 +1330,7 @@ mod replies { let mut reply = Reply::new(); reply.add(doc1); reply.add(doc2); - let mut reply_iter = reply.into_iter(); + let mut reply_iter = reply.iter(); let mut result1 = reply_iter.next().unwrap(); match result1.get_field(&fieldname).unwrap() { Field::StaticString(output) => assert_eq!(output, "one"), @@ -1432,6 +1487,10 @@ impl DocumentFile { } } + fn get_documents<'a>(&self) -> impl Iterator { + self.docs.iter() + } + fn add_document(&mut self, addition: &Addition) -> MsgAction { let mut holder = Document::new(); let doc = addition.get_document(); @@ -1464,11 +1523,7 @@ impl DocumentFile { } fn query(&self, query: &Query) -> MsgAction { - let mut reply = Reply::new(); - for doc in self.docs.iter() { - reply.add(doc.clone()); - } - reply.into() + query.run(self).into() } } @@ -1609,7 +1664,7 @@ mod document_files { match result.get_action() { MsgAction::Reply(output) => { assert_eq!(output.len(), 1); - let holder = output.clone().into_iter().next().unwrap(); + let holder = output.iter().next().unwrap(); match holder.get_field(name) { Some(field) => match field { Field::Uuid(store) => assert_eq!(store, &data), @@ -1630,7 +1685,7 @@ mod document_files { match result.get_action() { MsgAction::Reply(output) => { assert_eq!(output.len(), 1); - let holder = output.clone().into_iter().next().unwrap(); + let holder = output.iter().next().unwrap(); match holder.get_field(name) { Some(field) => match field { Field::Uuid(store) => assert_eq!(store, &data), @@ -1750,6 +1805,48 @@ mod document_files { _ => unreachable!("got {:?}: should have been an error", result.get_action()), } } + + #[test] + fn does_query_return_related_entries() { + let doc_name = "query"; + let (queue, rx) = test_doc(doc_name, create_docdef(2), standard_routes()); + let field0 = Uuid::new_v4(); + let field1 = Uuid::new_v4(); + for _ in 0..3 { + let mut addition = Addition::new(); + addition.add_field("field0".to_string(), Uuid::new_v4()); + addition.add_field("field1".to_string(), Uuid::new_v4()); + let msg = Message::new(doc_name, addition); + queue.send(msg).unwrap(); + rx.recv_timeout(TIMEOUT).unwrap(); + } + let mut addition = Addition::new(); + addition.add_field("field0".to_string(), field0.clone()); + addition.add_field("field1".to_string(), field1.clone()); + let msg = Message::new(doc_name, addition); + queue.send(msg).unwrap(); + rx.recv_timeout(TIMEOUT).unwrap(); + for _ in 0..3 { + let mut addition = Addition::new(); + addition.add_field("field0".to_string(), Uuid::new_v4()); + addition.add_field("field1".to_string(), Uuid::new_v4()); + let msg = Message::new(doc_name, addition); + queue.send(msg).unwrap(); + rx.recv_timeout(TIMEOUT).unwrap(); + } + let mut query = Query::new(); + query.add_specifier("field0".to_string(), Operand::Equal, field0.clone()); + let msg = Message::new(doc_name, query); + 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, "should return one entry"); + } + _ => unreachable!("got {:?}: should have been a reply", action), + } + } } #[cfg(test)]