diff --git a/src/errors.rs b/src/errors.rs index d23576f443a8375aefec7a32b4d858e70e9d42fb..3be37dd75237afc183c05d76447399a67892f358 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -4,6 +4,7 @@ use serde::Serialize; const BUCKET_ID_ERROR: &str = "field doesn't contains sharding key value"; const DUPLICATE_COLUMN_ERROR: &str = "duplicate column"; +const INVALID_NUMBER_ERROR: &str = "invalid number"; const INVALID_PLAN_ERROR: &str = "invalid plan"; const INVALID_RELATION_ERROR: &str = "invalid relation"; const INVALID_ROW_ERROR: &str = "invalid row"; @@ -19,6 +20,7 @@ const INCORRECT_BUCKET_ID_ERROR: &str = "incorrect bucket id"; pub enum QueryPlannerError { BucketIdError, DuplicateColumn, + InvalidNumber, InvalidPlan, InvalidRelation, InvalidRow, @@ -36,6 +38,7 @@ impl fmt::Display for QueryPlannerError { let p = match self { QueryPlannerError::BucketIdError => BUCKET_ID_ERROR, QueryPlannerError::DuplicateColumn => DUPLICATE_COLUMN_ERROR, + QueryPlannerError::InvalidNumber => INVALID_NUMBER_ERROR, QueryPlannerError::InvalidPlan => INVALID_PLAN_ERROR, QueryPlannerError::InvalidRelation => INVALID_RELATION_ERROR, QueryPlannerError::InvalidRow => INVALID_ROW_ERROR, diff --git a/src/ir.rs b/src/ir.rs index d7a29212bccdf54f1c2ad75a9c4e67c6416a0c6e..9946783945d4810d76bd7aa80ed8495953b37468 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -95,10 +95,13 @@ impl Plan { /// # Errors /// Returns `QueryPlannerError` when the plan tree check fails. pub fn check(&self) -> Result<(), QueryPlannerError> { - if self.top.is_none() { - return Err(QueryPlannerError::InvalidPlan); - } else if self.nodes.get(self.top.unwrap()).is_none() { - return Err(QueryPlannerError::ValueOutOfRange); + match self.top { + None => return Err(QueryPlannerError::InvalidPlan), + Some(top) => { + if self.nodes.get(top).is_none() { + return Err(QueryPlannerError::ValueOutOfRange); + } + } } //TODO: additional consistency checks diff --git a/src/ir/value.rs b/src/ir/value.rs index ab1dfc12ef5fbf7afe559bc7a6a26b485700dc3d..a3d990d0ac0ba97ca13f1745569a5dd59d98d373 100644 --- a/src/ir/value.rs +++ b/src/ir/value.rs @@ -1,5 +1,6 @@ //! Value module. +use crate::errors::QueryPlannerError; use decimal::d128; use serde::{Deserialize, Serialize}; use std::fmt; @@ -54,11 +55,14 @@ impl fmt::Display for Value { #[allow(dead_code)] impl Value { /// Construct a number from the string. - // FIXME: remove panic - #[must_use] - pub fn number_from_str(f: &str) -> Self { - let d = d128::from_str(&f.to_string()).unwrap(); - Value::Number(d) + /// + /// # Errors + /// Returns `QueryPlannerError` when a string is not a number. + pub fn number_from_str(f: &str) -> Result<Self, QueryPlannerError> { + if let Ok(d) = d128::from_str(&f.to_string()) { + return Ok(Value::Number(d)); + } + Err(QueryPlannerError::InvalidNumber) } /// Construct a string from the Rust `String`. @@ -69,7 +73,6 @@ impl Value { /// Check equality of the two values. /// Result uses three-valued logic. - // FIXME: remove panic #[must_use] pub fn eq(&self, other: &Value) -> Trivalent { match &*self { @@ -80,15 +83,13 @@ impl Value { }, Value::Null => Trivalent::Unknown, Value::Number(s) => match other { - Value::Boolean(_) => Trivalent::False, + Value::Boolean(_) | Value::String(_) => Trivalent::False, Value::Null => Trivalent::Unknown, Value::Number(o) => (s == o).into(), - Value::String(o) => (s == &d128::from_str(&o.to_string()).unwrap()).into(), }, Value::String(s) => match other { - Value::Boolean(_) => Trivalent::False, + Value::Boolean(_) | Value::Number(_) => Trivalent::False, Value::Null => Trivalent::Unknown, - Value::Number(o) => (o == &d128::from_str(&s.to_string()).unwrap()).into(), Value::String(o) => s.eq(o).into(), }, } @@ -116,7 +117,7 @@ mod tests { let v = Value::number_from_str(s); let d = d128::from_str(&s.to_string()).unwrap(); - if let Value::Number(n) = v { + if let Ok(Value::Number(n)) = v { assert_eq!(d, n); } else { panic!("incorrect enum!"); @@ -126,7 +127,7 @@ mod tests { fn test_nan(s: &str) { let v = Value::number_from_str(s); - if let Value::Number(n) = v { + if let Ok(Value::Number(n)) = v { assert_eq!(true, n.is_nan()); } else { panic!("incorrect enum!"); @@ -185,7 +186,7 @@ mod tests { ); assert_eq!( Trivalent::False, - Value::Boolean(true).eq(&Value::number_from_str("1e0")) + Value::Boolean(true).eq(&Value::number_from_str("1e0").unwrap()) ); assert_eq!( Trivalent::False, @@ -202,7 +203,7 @@ mod tests { assert_eq!(Trivalent::Unknown, Value::Null.eq(&Value::Boolean(false))); assert_eq!( Trivalent::Unknown, - Value::Null.eq(&Value::number_from_str("nan")) + Value::Null.eq(&Value::number_from_str("nan").unwrap()) ); assert_eq!( Trivalent::Unknown, @@ -212,35 +213,49 @@ mod tests { // Number assert_eq!( Trivalent::False, - Value::number_from_str("nan").eq(&Value::string_from_str("nan")) + Value::number_from_str("nan") + .unwrap() + .eq(&Value::string_from_str("nan")) ); assert_eq!( Trivalent::False, - Value::number_from_str("0").eq(&Value::Boolean(false)) + Value::number_from_str("0") + .unwrap() + .eq(&Value::Boolean(false)) ); assert_eq!( Trivalent::False, - Value::number_from_str("inf").eq(&Value::number_from_str("nan")) + Value::number_from_str("inf") + .unwrap() + .eq(&Value::number_from_str("nan").unwrap()) ); assert_eq!( Trivalent::False, - Value::number_from_str("-inf").eq(&Value::number_from_str("hello")) + Value::number_from_str("-inf") + .unwrap() + .eq(&Value::number_from_str("hello").unwrap()) ); assert_eq!( Trivalent::False, - Value::number_from_str("1e0").eq(&Value::number_from_str("1e100")) + Value::number_from_str("1e0") + .unwrap() + .eq(&Value::number_from_str("1e100").unwrap()) ); assert_eq!( Trivalent::True, - Value::number_from_str("1e0").eq(&Value::number_from_str("1.0e0")) + Value::number_from_str("1e0") + .unwrap() + .eq(&Value::number_from_str("1.0e0").unwrap()) ); assert_eq!( Trivalent::True, - Value::number_from_str("1e0").eq(&Value::number_from_str("1E0")) + Value::number_from_str("1e0") + .unwrap() + .eq(&Value::number_from_str("1E0").unwrap()) ); assert_eq!( Trivalent::Unknown, - Value::number_from_str("inf").eq(&Value::Null) + Value::number_from_str("inf").unwrap().eq(&Value::Null) ); // String