diff --git a/src/action/calculation.rs b/src/action/calculation.rs index ac23ba9..9e1ac14 100644 --- a/src/action/calculation.rs +++ b/src/action/calculation.rs @@ -309,12 +309,10 @@ impl Calculation { } } - #[allow(dead_code)] fn operation(&self) -> &Operand { &self.operation } - #[allow(dead_code)] fn get_fields(&self, existing: Field) -> Vec { let mut output = Vec::new(); for item in self.values.iter() { @@ -358,7 +356,6 @@ impl Calculation { Ok(()) } - #[allow(dead_code)] fn validate_value(&self, value: CV) -> Result<(), MTTError> where CV: Into, @@ -401,38 +398,36 @@ impl Calculation { } } Operand::Equal => { - if self.values.len() >= 2 { - result = self.values[0] - .get(existing) - .equal(&self.values[1].get(existing)); + if self.values.len() == 2 { + result = Field::Boolean( + self.values[0].get(existing) == self.values[1].get(existing), + ); } } Operand::GreaterThan => { - if self.values.len() >= 2 { - result = self.values[0] - .get(existing) - .greater(&self.values[1].get(existing)); + if self.values.len() == 2 { + result = + Field::Boolean(self.values[0].get(existing) > self.values[1].get(existing)); } } Operand::GreaterThanEqual => { - if self.values.len() >= 2 { - result = self.values[0] - .get(existing) - .greater_equal(&self.values[1].get(existing)); + if self.values.len() == 2 { + result = Field::Boolean( + self.values[0].get(existing) >= self.values[1].get(existing), + ); } } Operand::LessThan => { - if self.values.len() >= 2 { - result = self.values[0] - .get(existing) - .lesser(&self.values[1].get(existing)); + if self.values.len() == 2 { + result = + Field::Boolean(self.values[0].get(existing) < self.values[1].get(existing)); } } Operand::LessThanEqual => { - if self.values.len() >= 2 { - result = self.values[0] - .get(existing) - .lesser_equal(&self.values[1].get(existing)); + if self.values.len() == 2 { + result = Field::Boolean( + self.values[0].get(existing) <= self.values[1].get(existing), + ); } } } diff --git a/src/document/create.rs b/src/document/create.rs index dcce513..672ffcb 100644 --- a/src/document/create.rs +++ b/src/document/create.rs @@ -1203,7 +1203,6 @@ mod document_files { _ => unreachable!("got {:?}: should have been an error", result.get_action()), } } - */ #[test] fn does_query_return_related_entries() { @@ -1313,6 +1312,7 @@ mod document_files { _ => unreachable!("got {:?}: should have been a reply", action), } } + */ #[test] fn query_should_work_with_multiple_fields() { diff --git a/src/document/field.rs b/src/document/field.rs index a3bc8e3..8a6585f 100644 --- a/src/document/field.rs +++ b/src/document/field.rs @@ -1,11 +1,12 @@ use chrono::prelude::*; use std::{ + cmp::Ordering, ops::{Add, AddAssign}, time::Duration, }; use uuid::Uuid; -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq)] pub enum Field { Boolean(bool), DateTime(DateTime), @@ -21,54 +22,6 @@ impl Field { pub fn get_type(&self) -> FieldType { self.into() } - - pub fn equal(&self, other: &Field) -> Field { - if self.get_type() == other.get_type() { - { self == other }.into() - } else { - Field::None - } - } - - pub fn not_equal(&self, other: &Field) -> Field { - if self.get_type() == other.get_type() { - { self != other }.into() - } else { - Field::None - } - } - - pub fn greater(&self, other: &Self) -> Field { - if self.get_type() == other.get_type() { - { self > other }.into() - } else { - Field::None - } - } - - pub fn greater_equal(&self, other: &Self) -> Field { - if self.get_type() == other.get_type() { - { self >= other }.into() - } else { - Field::None - } - } - - pub fn lesser(&self, other: &Self) -> Field { - if self.get_type() == other.get_type() { - { self < other }.into() - } else { - Field::None - } - } - - pub fn lesser_equal(&self, other: &Self) -> Field { - if self.get_type() == other.get_type() { - { self <= other }.into() - } else { - Field::None - } - } } impl Add for Field { @@ -161,6 +114,21 @@ impl From for Field { } } +impl PartialOrd for Field { + fn partial_cmp(&self, other: &Field) -> Option { + match (self, other) { + (Self::Boolean(d1), Self::Boolean(d2)) => d1.partial_cmp(d2), + (Self::DateTime(d1), Self::DateTime(d2)) => d1.partial_cmp(d2), + (Self::Duration(d1), Self::Duration(d2)) => d1.partial_cmp(d2), + (Self::Integer(d1), Self::Integer(d2)) => d1.partial_cmp(d2), + (Self::Revision(d1), Self::Revision(d2)) => d1.partial_cmp(d2), + (Self::StaticString(d1), Self::StaticString(d2)) => d1.partial_cmp(d2), + (Self::Uuid(d1), Self::Uuid(d2)) => d1.partial_cmp(d2), + (_, _) => None, + } + } +} + #[cfg(test)] mod fields { use super::*; @@ -272,81 +240,33 @@ mod fields { } #[test] - fn does_field_equal_return_properly() { - let mut values: Vec = Vec::new(); - let count = 2; - while values.len() < count { - let value: Field = Uuid::new_v4().into(); - if !values.contains(&value) { - values.push(value); - } - } - assert_eq!(values[0].equal(&values[0]), true.into()); - assert_eq!(values[0].equal(&values[1]), false.into()); - assert_eq!(values[0].equal(&"nope".into()), Field::None); + fn do_comparason_functions_work() { + let fields = [Field::Integer(0), Field::Integer(1), Field::Integer(2)]; + assert!(fields[1] == fields[1], "equal did not work"); + assert!(fields[1] < fields[2], "less than did not work"); + assert!(fields[1] <= fields[2], "less than equal to did not work"); + assert!(fields[1] <= fields[1], "less tahn equal 50 did not work"); + assert!(fields[1] > fields[0], "greater than did not work"); + assert!(fields[1] >= fields[0], "greater than equal to did not work"); + assert!(fields[1] >= fields[1], "greater than equal to did not work"); } #[test] - fn does_field_not_equal_return_properly() { - let mut values: Vec = Vec::new(); - let count = 2; - while values.len() < count { - let value: Field = Uuid::new_v4().into(); - if !values.contains(&value) { - values.push(value); - } - } - assert_eq!(values[0].not_equal(&values[0]), false.into()); - assert_eq!(values[0].not_equal(&values[1]), true.into()); - assert_eq!(values[0].not_equal(&"nope".into()), Field::None); - } - - #[test] - fn can_field_have_greater_value() { - let value1: Field = 1.into(); - let value2: Field = 2.into(); - let value3: Field = 3.into(); - let mismatch: Field = "bad".into(); - assert_eq!(value2.greater(&value1), true.into()); - assert_eq!(value2.greater(&value2), false.into()); - assert_eq!(value2.greater(&value3), false.into()); - assert_eq!(value2.greater(&mismatch), Field::None); - } - - #[test] - fn can_field_have_greater_or_equal_value() { - let value1: Field = 1.into(); - let value2: Field = 2.into(); - let value3: Field = 3.into(); - let mismatch: Field = "bad".into(); - assert_eq!(value2.greater_equal(&value1), true.into()); - assert_eq!(value2.greater_equal(&value2), true.into()); - assert_eq!(value2.greater_equal(&value3), false.into()); - assert_eq!(value2.greater_equal(&mismatch), Field::None); - } - - #[test] - fn can_field_have_lesser_value() { - let value1: Field = 1.into(); - let value2: Field = 2.into(); - let value3: Field = 3.into(); - let mismatch: Field = "bad".into(); - assert_eq!(value2.lesser(&value1), false.into()); - assert_eq!(value2.lesser(&value2), false.into()); - assert_eq!(value2.lesser(&value3), true.into()); - assert_eq!(value2.lesser(&mismatch), Field::None); - } - - #[test] - fn can_field_have_lesser_or_equal_value() { - let value1: Field = 1.into(); - let value2: Field = 2.into(); - let value3: Field = 3.into(); - let mismatch: Field = "bad".into(); - assert_eq!(value2.lesser_equal(&value1), false.into()); - assert_eq!(value2.lesser_equal(&value2), true.into()); - assert_eq!(value2.lesser_equal(&value3), true.into()); - assert_eq!(value2.lesser_equal(&mismatch), Field::None); + fn does_mismatched_comparason_fields_return_false() { + let fields = [Field::Integer(0), Field::Uuid(Uuid::nil())]; + assert!(!(fields[0] == fields[1]), "equal did not work"); + assert!(!(fields[0] < fields[1]), "less than did not work"); + assert!(!(fields[0] <= fields[1]), "less than equal to did not work"); + assert!(!(fields[0] <= fields[1]), "less tahn equal 50 did not work"); + assert!(!(fields[1] > fields[0]), "greater than did not work"); + assert!( + !(fields[1] >= fields[0]), + "greater than equal to did not work" + ); + assert!( + !(fields[1] >= fields[0]), + "greater than equal to did not work" + ); } } diff --git a/tests/query_test.rs b/tests/query_test.rs new file mode 100644 index 0000000..e720b94 --- /dev/null +++ b/tests/query_test.rs @@ -0,0 +1,151 @@ +mod support; + +use morethantext::{CalcValue, Calculation, Field, FieldType, MoreThanText, Operand, Query}; +use std::collections::HashSet; +use support::TestDocument; + +const COUNT: usize = 5; + +fn setup_range() -> (MoreThanText, TestDocument) { + let mut mtt = MoreThanText::new(); + let test_doc = TestDocument::new(vec![FieldType::Integer]); + mtt.create_document(test_doc.get_docdef()).unwrap(); + let mut data: Vec> = Vec::new(); + for i in 0..COUNT { + let holder: i128 = i.try_into().unwrap(); + data.push(vec![holder]); + } + test_doc.populate_multiple(&mut mtt, data); + (mtt, test_doc) +} + +#[test] +fn does_empty_query_get_all_documents() { + let (mut mtt, test_doc) = setup_range(); + let mut query = Query::new(test_doc.get_doc_name()); + let result = mtt.records(query).unwrap(); + assert_eq!(result.len(), 5, "got {:?}", result); + let mut holder: HashSet = HashSet::new(); + for rec in result.iter() { + holder.insert(rec.get(test_doc.get_field_name(0)).unwrap()); + } + assert_eq!(holder.len(), COUNT, "got {:?}", holder); + for i in 0..COUNT { + let data: i128 = i.try_into().unwrap(); + holder.remove(&data.into()); + } + assert_eq!(holder.len(), 0, "got {:?}", holder); +} + +#[test] +fn does_query_pull_specific_information() { + let (mut mtt, test_doc) = setup_range(); + let expected = 3; + let mut calc = Calculation::new(Operand::Equal); + calc.add_value(expected.clone()).unwrap(); + calc.add_value(CalcValue::Existing(FieldType::Integer)) + .unwrap(); + let mut query = Query::new(test_doc.get_doc_name()); + query.add(test_doc.get_field_name(0), calc); + let result = mtt.records(query).unwrap(); + assert_eq!(result.len(), 1); + let rec = result.iter().last().unwrap(); + assert_eq!( + rec.get(test_doc.get_field_name(0)).unwrap(), + expected.into() + ); +} + +#[test] +fn does_query_work_with_less_than() { + let (mut mtt, test_doc) = setup_range(); + let expected = 2; + let mut calc = Calculation::new(Operand::LessThan); + calc.add_value(expected.clone()).unwrap(); + calc.add_value(CalcValue::Existing(FieldType::Integer)) + .unwrap(); + let mut query = Query::new(test_doc.get_doc_name()); + query.add(test_doc.get_field_name(0), calc); + let result = mtt.records(query).unwrap(); + assert_eq!(result.len(), 2, "got {:?}", result); + let mut holder: HashSet = HashSet::new(); + for rec in result.iter() { + holder.insert(rec.get(test_doc.get_field_name(0)).unwrap()); + } + assert_eq!(holder.len(), 2, "got {:?}", holder); + for i in 3..COUNT { + let data: i128 = i.try_into().unwrap(); + holder.remove(&data.into()); + } + assert_eq!(holder.len(), 0, "got {:?}", holder); +} + +#[test] +fn does_query_work_with_less_than_equal() { + let (mut mtt, test_doc) = setup_range(); + let expected = 2; + let mut calc = Calculation::new(Operand::LessThanEqual); + calc.add_value(expected.clone()).unwrap(); + calc.add_value(CalcValue::Existing(FieldType::Integer)) + .unwrap(); + let mut query = Query::new(test_doc.get_doc_name()); + query.add(test_doc.get_field_name(0), calc); + let result = mtt.records(query).unwrap(); + assert_eq!(result.len(), 3, "got {:?}", result); + let mut holder: HashSet = HashSet::new(); + for rec in result.iter() { + holder.insert(rec.get(test_doc.get_field_name(0)).unwrap()); + } + assert_eq!(holder.len(), 3, "got {:?}", holder); + for i in 2..COUNT { + let data: i128 = i.try_into().unwrap(); + holder.remove(&data.into()); + } + assert_eq!(holder.len(), 0, "got {:?}", holder); +} + +#[test] +fn does_query_work_with_greater_than() { + let (mut mtt, test_doc) = setup_range(); + let expected = 2; + let mut calc = Calculation::new(Operand::GreaterThan); + calc.add_value(expected.clone()).unwrap(); + calc.add_value(CalcValue::Existing(FieldType::Integer)) + .unwrap(); + let mut query = Query::new(test_doc.get_doc_name()); + query.add(test_doc.get_field_name(0), calc); + let result = mtt.records(query).unwrap(); + assert_eq!(result.len(), 2, "got {:?}", result); + let mut holder: HashSet = HashSet::new(); + for rec in result.iter() { + holder.insert(rec.get(test_doc.get_field_name(0)).unwrap()); + } + assert_eq!(holder.len(), 2, "got {:?}", holder); + for i in 0..2 { + holder.remove(&i.into()); + } + assert_eq!(holder.len(), 0, "got {:?}", holder); +} + +#[test] +fn does_query_work_with_greater_than_equal() { + let (mut mtt, test_doc) = setup_range(); + let expected = 2; + let mut calc = Calculation::new(Operand::GreaterThanEqual); + calc.add_value(expected.clone()).unwrap(); + calc.add_value(CalcValue::Existing(FieldType::Integer)) + .unwrap(); + let mut query = Query::new(test_doc.get_doc_name()); + query.add(test_doc.get_field_name(0), calc); + let result = mtt.records(query).unwrap(); + assert_eq!(result.len(), 3, "got {:?}", result); + let mut holder: HashSet = HashSet::new(); + for rec in result.iter() { + holder.insert(rec.get(test_doc.get_field_name(0)).unwrap()); + } + assert_eq!(holder.len(), 3, "got {:?}", holder); + for i in 0..3 { + holder.remove(&i.into()); + } + assert_eq!(holder.len(), 0, "got {:?}", holder); +} diff --git a/tests/support.rs b/tests/support.rs index e6a8dd1..3bac50a 100644 --- a/tests/support.rs +++ b/tests/support.rs @@ -41,12 +41,18 @@ impl TestDocument { self.field_names[position].clone() } - pub fn populate(&self, mtt: &mut MoreThanText, data: Vec) where F: Into + Clone { + pub fn populate(&self, mtt: &mut MoreThanText, data: Vec) + where + F: Into + Clone, + { let wrapper = vec![data]; self.populate_multiple(mtt, wrapper); } - pub fn populate_multiple(&self, mtt: &mut MoreThanText, data: Vec>) where F: Into + Clone { + pub fn populate_multiple(&self, mtt: &mut MoreThanText, data: Vec>) + where + F: Into + Clone, + { for rec in data.iter() { let mut add = Addition::new(self.doc_name.clone()); for i in 0..self.field_names.len() {