Repository: gluesql/gluesql
Pull request #116 (2020-11-20 01:58:33)

Allow Binary Operations Between <i64> and <f64>
This PR would be a simple expansion of binary operations. :) `evaluated.rs` now handles binary operations between <i64> and <f64>. To check the code, I added some test cases in `filter.rs`. Examples of test cases are
```
(5, "SELECT name FROM Boss WHERE 2 = 1.0 + 1"),
(3, "SELECT id FROM Hunter WHERE -1.0 - 1.0 < -1")
``` 


Patch:
diff --git a/src/executor/evaluate/evaluated.rs b/src/executor/evaluate/evaluated.rs
index a93fa34a..fd9a3ba5 100644
--- a/src/executor/evaluate/evaluated.rs
+++ b/src/executor/evaluate/evaluated.rs
@@ -129,7 +129,7 @@ impl<'a> PartialOrd for Evaluated<'a> {
                 ValueRef(data::Value::Str(r)) => l.partial_cmp(&r.as_str()),
                 Value(data::Value::Str(r)) => l.partial_cmp(&r.as_str()),
                 StringRef(r) => l.partial_cmp(r),
-                Literal(_) => panic!(),
+                Literal(_) => None,
                 _ => None,
             },
             Literal(l) => match other {
@@ -345,56 +345,46 @@ impl<'a> Evaluated<'a> {
     }
 }
 
-fn literal_add(a: &AstValue, b: &AstValue) -> Result<AstValue> {
-    match (a, b) {
-        (AstValue::Number(a), AstValue::Number(b)) => match (a.parse::<i64>(), b.parse::<i64>()) {
-            (Ok(a), Ok(b)) => Ok(AstValue::Number((a + b).to_string())),
-            _ => panic!(),
-        },
-        (AstValue::Null, AstValue::Number(_)) | (AstValue::Number(_), AstValue::Null) => {
-            Ok(AstValue::Null)
+macro_rules! literal_binary_op {
+    ($e1:expr, $e2:expr, $op:tt) => {
+        match ($e1, $e2) {
+            (AstValue::Number(a), AstValue::Number(b)) => match (a.parse::<i64>(), b.parse::<i64>()) {
+                (Ok(a), Ok(b)) => Ok(AstValue::Number((a $op b).to_string())),
+                (Ok(a), _) => match b.parse::<f64>() {
+                    Ok(b) => Ok(AstValue::Number(((a as f64) $op b).to_string())),
+                    _ => Err(EvaluateError::UnreachableLiteralArithmetic.into()),
+                },
+                (_, Ok(b)) => match a.parse::<f64>() {
+                    Ok(a) => Ok(AstValue::Number((a $op (b as f64)).to_string())),
+                    _ => Err(EvaluateError::UnreachableLiteralArithmetic.into()),
+                },
+                (_, _) => match (a.parse::<f64>(), b.parse::<f64>()) {
+                    (Ok(a), Ok(b)) => Ok(AstValue::Number((a $op b).to_string())),
+                    _ => Err(EvaluateError::UnreachableLiteralArithmetic.into()),
+                },
+            },
+            (AstValue::Null, AstValue::Number(_)) | (AstValue::Number(_), AstValue::Null) => {
+                Ok(AstValue::Null)
+            }
+            _ => Err(EvaluateError::UnreachableLiteralArithmetic.into()),
         }
-        _ => Err(EvaluateError::UnreachableLiteralArithmetic.into()),
-    }
+    };
+}
+
+fn literal_add(a: &AstValue, b: &AstValue) -> Result<AstValue> {
+    literal_binary_op!(a, b, +)
 }
 
 fn literal_subtract(a: &AstValue, b: &AstValue) -> Result<AstValue> {
-    match (a, b) {
-        (AstValue::Number(a), AstValue::Number(b)) => match (a.parse::<i64>(), b.parse::<i64>()) {
-            (Ok(a), Ok(b)) => Ok(AstValue::Number((a - b).to_string())),
-            _ => panic!(),
-        },
-        (AstValue::Null, AstValue::Number(_)) | (AstValue::Number(_), AstValue::Null) => {
-            Ok(AstValue::Null)
-        }
-        _ => Err(EvaluateError::UnreachableLiteralArithmetic.into()),
-    }
+    literal_binary_op!(a, b, -)
 }
 
 fn literal_multiply(a: &AstValue, b: &AstValue) -> Result<AstValue> {
-    match (a, b) {
-        (AstValue::Number(a), AstValue::Number(b)) => match (a.parse::<i64>(), b.parse::<i64>()) {
-            (Ok(a), Ok(b)) => Ok(AstValue::Number((a * b).to_string())),
-            _ => panic!(),
-        },
-        (AstValue::Null, AstValue::Number(_)) | (AstValue::Number(_), AstValue::Null) => {
-            Ok(AstValue::Null)
-        }
-        _ => Err(EvaluateError::UnreachableLiteralArithmetic.into()),
-    }
+    literal_binary_op!(a, b, *)
 }
 
 fn literal_divide(a: &AstValue, b: &AstValue) -> Result<AstValue> {
-    match (a, b) {
-        (AstValue::Number(a), AstValue::Number(b)) => match (a.parse::<i64>(), b.parse::<i64>()) {
-            (Ok(a), Ok(b)) => Ok(AstValue::Number((a / b).to_string())),
-            _ => panic!(),
-        },
-        (AstValue::Null, AstValue::Number(_)) | (AstValue::Number(_), AstValue::Null) => {
-            Ok(AstValue::Null)
-        }
-        _ => Err(EvaluateError::UnreachableLiteralArithmetic.into()),
-    }
+    literal_binary_op!(a, b, /)
 }
 
 fn literal_plus(v: &AstValue) -> Result<AstValue> {


Test patch:
diff --git a/src/tests/filter.rs b/src/tests/filter.rs
index 40a46cf5..60103489 100644
--- a/src/tests/filter.rs
+++ b/src/tests/filter.rs
@@ -76,6 +76,17 @@ test_case!(filter, async move {
         count!(*num, sql);
     }
 
+    let select_opt_sqls = [
+        (5, "SELECT name FROM Boss WHERE 2 = 1.0 + 1"),
+        (3, "SELECT id FROM Hunter WHERE -1.0 - 1.0 < -1"),
+        (5, "SELECT name FROM Boss WHERE -2.0 * -3.0 = 6"),
+        (3, "SELECT id FROM Hunter WHERE +2 / 1.0 > +1.0"),
+    ];
+
+    for (num, sql) in select_opt_sqls.iter() {
+        count!(*num, sql);
+    }
+
     let error_sqls = vec![
         (
             EvaluateError::LiteralUnaryPlusOnNonNumeric.into(),