From 163b7108e30ed2fc7b171383afb38cc29906be10 Mon Sep 17 00:00:00 2001 From: Daniel Gerlag Date: Wed, 17 Jul 2024 11:59:48 -0700 Subject: [PATCH] additional test cases --- core/src/evaluation/expressions/mod.rs | 10 +- .../expressions/tests/list_construction.rs | 25 + .../expressions/tests/list_reduce.rs | 532 +++++++++++------- core/src/evaluation/parts/tests/multi_part.rs | 2 +- 4 files changed, 369 insertions(+), 200 deletions(-) diff --git a/core/src/evaluation/expressions/mod.rs b/core/src/evaluation/expressions/mod.rs index 7b31cc1..00696dd 100644 --- a/core/src/evaluation/expressions/mod.rs +++ b/core/src/evaluation/expressions/mod.rs @@ -8,7 +8,7 @@ use async_recursion::async_recursion; use chrono::{ Datelike, Duration, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Weekday, }; -use drasi_query_ast::ast::{self, ParentExpression}; +use drasi_query_ast::ast; use crate::evaluation::temporal_constants; use crate::evaluation::variable_value::duration::Duration as DurationStruct; @@ -21,7 +21,7 @@ use crate::interface::{ResultKey, ResultOwner}; use crate::{evaluation::variable_value::VariableValue, interface::ResultIndex}; use super::{ - context::{ExpressionEvaluationContext, QueryVariables, SideEffects}, + context::{ExpressionEvaluationContext, SideEffects}, functions::{aggregation::Accumulator, Function, FunctionRegistry}, EvaluationError, }; @@ -1631,7 +1631,10 @@ impl ExpressionEvaluator { .await?; match items { VariableValue::List(items) => { - let mut result = VariableValue::Null; + let mut result = match context.get_variable(accumulator_variable.clone()) { + Some(value) => value.clone(), + None => VariableValue::Null, + }; let mut variables = context.clone_variables(); for item in items { if let Some(filter) = &expression.filter { @@ -1639,6 +1642,7 @@ impl ExpressionEvaluator { .insert(expression.item_identifier.to_string().into(), item.clone()); let local_context = ExpressionEvaluationContext::new(&variables, context.get_clock()); + if !self.evaluate_predicate(&local_context, filter).await? { continue; } diff --git a/core/src/evaluation/expressions/tests/list_construction.rs b/core/src/evaluation/expressions/tests/list_construction.rs index fb332c2..5b9e078 100644 --- a/core/src/evaluation/expressions/tests/list_construction.rs +++ b/core/src/evaluation/expressions/tests/list_construction.rs @@ -94,6 +94,31 @@ async fn test_list_comprehension_property_with_mapping_only() { ); } +#[tokio::test] +async fn test_list_comprehension_property_with_mapping_only_non_numeric() { + let expr = "[x IN ['foo', 'bar'] | x + 'baz']"; + + let expr = drasi_query_cypher::parse_expression(expr).unwrap(); + let function_registry = Arc::new(FunctionRegistry::new()); + let ari = Arc::new(InMemoryResultIndex::new()); + let evaluator = ExpressionEvaluator::new(function_registry.clone(), ari.clone()); + + let variables = QueryVariables::new(); + let context = + ExpressionEvaluationContext::new(&variables, Arc::new(InstantQueryClock::new(0, 0))); + + assert_eq!( + evaluator + .evaluate_expression(&context, &expr) + .await + .unwrap(), + VariableValue::List(vec![ + VariableValue::String(String::from("foobaz")), + VariableValue::String(String::from("barbaz")), + ]) + ); +} + #[tokio::test] async fn test_list_comprehension_property() { let expr = "[x IN [123,342,12,34,-12] where x > 0| x - 10]"; //for each element in param1, return the value property diff --git a/core/src/evaluation/expressions/tests/list_reduce.rs b/core/src/evaluation/expressions/tests/list_reduce.rs index 5b09741..05ac220 100644 --- a/core/src/evaluation/expressions/tests/list_reduce.rs +++ b/core/src/evaluation/expressions/tests/list_reduce.rs @@ -1,196 +1,336 @@ -use crate::evaluation::context::QueryVariables; -use crate::evaluation::functions::FunctionRegistry; -use crate::evaluation::variable_value::integer::Integer; -use crate::evaluation::variable_value::VariableValue; -use crate::evaluation::{ExpressionEvaluationContext, ExpressionEvaluator, InstantQueryClock}; -use crate::in_memory_index::in_memory_result_index::InMemoryResultIndex; -use std::collections::BTreeMap; -use std::sync::Arc; - -#[tokio::test] -async fn evaluate_reduce_func() { - let expr = "reduce(acc = 0, x IN [1,2,3] | acc + x)"; - - let expr = drasi_query_cypher::parse_expression(expr).unwrap(); - - let function_registry = Arc::new(FunctionRegistry::new()); - let ari = Arc::new(InMemoryResultIndex::new()); - let evaluator = ExpressionEvaluator::new(function_registry.clone(), ari.clone()); - - let variables = QueryVariables::new(); - - let context = - ExpressionEvaluationContext::new(&variables, Arc::new(InstantQueryClock::new(0, 0))); - assert_eq!( - evaluator - .evaluate_expression(&context, &expr) - .await - .unwrap(), - VariableValue::Integer(Integer::from(6)) - ); -} - -#[tokio::test] -async fn evaluate_reduce_func_min_temp() { - let expr = "reduce ( minTemp = 0.0, sensorValVersion IN [11.2, 431, -75, 24] | - CASE WHEN sensorValVersion < minTemp THEN sensorValVersion - ELSE minTemp END)"; - - let expr = drasi_query_cypher::parse_expression(expr).unwrap(); - - let function_registry = Arc::new(FunctionRegistry::new()); - let ari = Arc::new(InMemoryResultIndex::new()); - let evaluator = ExpressionEvaluator::new(function_registry.clone(), ari.clone()); - - let variables = QueryVariables::new(); - - let context = - ExpressionEvaluationContext::new(&variables, Arc::new(InstantQueryClock::new(0, 0))); - assert_eq!( - evaluator - .evaluate_expression(&context, &expr) - .await - .unwrap(), - VariableValue::Integer(Integer::from(-75)) - ); -} - -#[tokio::test] -async fn evaluate_reduce_func_sensor_value() { - let expr = "reduce (total = 0.0, val IN $param1| total + val.value)"; - - let expr = drasi_query_cypher::parse_expression(expr).unwrap(); - - let function_registry = Arc::new(FunctionRegistry::new()); - let ari = Arc::new(InMemoryResultIndex::new()); - let evaluator = ExpressionEvaluator::new(function_registry.clone(), ari.clone()); - - let mut variables = QueryVariables::new(); - - let sensor_val_version_list = vec![ - VariableValue::Object({ - let mut map = BTreeMap::new(); - map.insert( - "value".to_string(), - VariableValue::Integer(Integer::from(11)), - ); - map - }), - VariableValue::Object({ - let mut map = BTreeMap::new(); - map.insert( - "value".to_string(), - VariableValue::Integer(Integer::from(86)), - ); - map - }), - VariableValue::Object({ - let mut map = BTreeMap::new(); - map.insert( - "value".to_string(), - VariableValue::Integer(Integer::from(3)), - ); - map - }), - VariableValue::Object({ - let mut map = BTreeMap::new(); - map.insert( - "value".to_string(), - VariableValue::Integer(Integer::from(121)), - ); - map - }), - VariableValue::Object({ - let mut map = BTreeMap::new(); - map.insert( - "value".to_string(), - VariableValue::Integer(Integer::from(-45)), - ); - map - }), - ]; - variables.insert( - "param1".to_string().into(), - VariableValue::List(sensor_val_version_list), - ); - let context = - ExpressionEvaluationContext::new(&variables, Arc::new(InstantQueryClock::new(0, 0))); - - assert_eq!( - evaluator - .evaluate_expression(&context, &expr) - .await - .unwrap(), - VariableValue::Float(176.0.into()) - ); -} - -#[tokio::test] -async fn evaluate_reduce_func_sensor_value_count() { - let expr = "reduce (count = 0, val IN $param1| count + 1)"; - - let expr = drasi_query_cypher::parse_expression(expr).unwrap(); - - let function_registry = Arc::new(FunctionRegistry::new()); - let ari = Arc::new(InMemoryResultIndex::new()); - let evaluator = ExpressionEvaluator::new(function_registry.clone(), ari.clone()); - - let mut variables = QueryVariables::new(); - - let sensor_val_version_list = vec![ - VariableValue::Object({ - let mut map = BTreeMap::new(); - map.insert( - "value".to_string(), - VariableValue::Integer(Integer::from(11)), - ); - map - }), - VariableValue::Object({ - let mut map = BTreeMap::new(); - map.insert( - "value".to_string(), - VariableValue::Integer(Integer::from(86)), - ); - map - }), - VariableValue::Object({ - let mut map = BTreeMap::new(); - map.insert( - "value".to_string(), - VariableValue::Integer(Integer::from(3)), - ); - map - }), - VariableValue::Object({ - let mut map = BTreeMap::new(); - map.insert( - "value".to_string(), - VariableValue::Integer(Integer::from(121)), - ); - map - }), - VariableValue::Object({ - let mut map = BTreeMap::new(); - map.insert( - "value".to_string(), - VariableValue::Integer(Integer::from(-45)), - ); - map - }), - ]; - variables.insert( - "param1".to_string().into(), - VariableValue::List(sensor_val_version_list), - ); - let context = - ExpressionEvaluationContext::new(&variables, Arc::new(InstantQueryClock::new(0, 0))); - - assert_eq!( - evaluator - .evaluate_expression(&context, &expr) - .await - .unwrap(), - VariableValue::Integer(5.into()) - ); -} +use crate::evaluation::context::QueryVariables; +use crate::evaluation::functions::FunctionRegistry; +use crate::evaluation::variable_value::integer::Integer; +use crate::evaluation::variable_value::VariableValue; +use crate::evaluation::{ExpressionEvaluationContext, ExpressionEvaluator, InstantQueryClock}; +use crate::in_memory_index::in_memory_result_index::InMemoryResultIndex; +use std::collections::BTreeMap; +use std::sync::Arc; + +#[tokio::test] +async fn evaluate_reduce_func() { + let expr = "reduce(acc = 0, x IN [1,2,3] | acc + x)"; + + let expr = drasi_query_cypher::parse_expression(expr).unwrap(); + + let function_registry = Arc::new(FunctionRegistry::new()); + let ari = Arc::new(InMemoryResultIndex::new()); + let evaluator = ExpressionEvaluator::new(function_registry.clone(), ari.clone()); + + let variables = QueryVariables::new(); + + let context = + ExpressionEvaluationContext::new(&variables, Arc::new(InstantQueryClock::new(0, 0))); + assert_eq!( + evaluator + .evaluate_expression(&context, &expr) + .await + .unwrap(), + VariableValue::Integer(Integer::from(6)) + ); +} + +#[tokio::test] +async fn evaluate_reduce_func_min_temp() { + let expr = "reduce ( minTemp = 0.0, sensorValVersion IN [11.2, 431, -75, 24] | + CASE WHEN sensorValVersion < minTemp THEN sensorValVersion + ELSE minTemp END)"; + + let expr = drasi_query_cypher::parse_expression(expr).unwrap(); + + let function_registry = Arc::new(FunctionRegistry::new()); + let ari = Arc::new(InMemoryResultIndex::new()); + let evaluator = ExpressionEvaluator::new(function_registry.clone(), ari.clone()); + + let variables = QueryVariables::new(); + + let context = + ExpressionEvaluationContext::new(&variables, Arc::new(InstantQueryClock::new(0, 0))); + assert_eq!( + evaluator + .evaluate_expression(&context, &expr) + .await + .unwrap(), + VariableValue::Integer(Integer::from(-75)) + ); +} + +#[tokio::test] +async fn evaluate_reduce_func_sensor_value() { + let expr = "reduce (total = 0.0, val IN $param1| total + val.value)"; + + let expr = drasi_query_cypher::parse_expression(expr).unwrap(); + + let function_registry = Arc::new(FunctionRegistry::new()); + let ari = Arc::new(InMemoryResultIndex::new()); + let evaluator = ExpressionEvaluator::new(function_registry.clone(), ari.clone()); + + let mut variables = QueryVariables::new(); + + let sensor_val_version_list = vec![ + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(11)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(86)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(3)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(121)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(-45)), + ); + map + }), + ]; + variables.insert( + "param1".to_string().into(), + VariableValue::List(sensor_val_version_list), + ); + let context = + ExpressionEvaluationContext::new(&variables, Arc::new(InstantQueryClock::new(0, 0))); + + assert_eq!( + evaluator + .evaluate_expression(&context, &expr) + .await + .unwrap(), + VariableValue::Float(176.0.into()) + ); +} + +#[tokio::test] +async fn evaluate_reduce_func_sensor_value_count() { + let expr = "reduce (count = 0, val IN $param1| count + 1)"; + + let expr = drasi_query_cypher::parse_expression(expr).unwrap(); + + let function_registry = Arc::new(FunctionRegistry::new()); + let ari = Arc::new(InMemoryResultIndex::new()); + let evaluator = ExpressionEvaluator::new(function_registry.clone(), ari.clone()); + + let mut variables = QueryVariables::new(); + + let sensor_val_version_list = vec![ + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(11)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(86)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(3)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(121)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(-45)), + ); + map + }), + ]; + variables.insert( + "param1".to_string().into(), + VariableValue::List(sensor_val_version_list), + ); + let context = + ExpressionEvaluationContext::new(&variables, Arc::new(InstantQueryClock::new(0, 0))); + + assert_eq!( + evaluator + .evaluate_expression(&context, &expr) + .await + .unwrap(), + VariableValue::Integer(5.into()) + ); +} + +#[tokio::test] +async fn evaluate_reduce_func_with_filter() { + let expr = "reduce (count = 0, val IN $param1 where val.value > 0| count + 1)"; + + let expr = drasi_query_cypher::parse_expression(expr).unwrap(); + + let function_registry = Arc::new(FunctionRegistry::new()); + let ari = Arc::new(InMemoryResultIndex::new()); + let evaluator = ExpressionEvaluator::new(function_registry.clone(), ari.clone()); + + let mut variables = QueryVariables::new(); + + let sensor_val_version_list = vec![ + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(11)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(86)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(3)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(121)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(-45)), + ); + map + }), + ]; + variables.insert( + "param1".to_string().into(), + VariableValue::List(sensor_val_version_list), + ); + let context = + ExpressionEvaluationContext::new(&variables, Arc::new(InstantQueryClock::new(0, 0))); + + assert_eq!( + evaluator + .evaluate_expression(&context, &expr) + .await + .unwrap(), + VariableValue::Integer(4.into()) + ); +} + +#[tokio::test] +async fn evaluate_reduce_func_with_filter_no_results() { + let expr = "reduce (count = 0, val IN $param1 where 1 = 0| count + 1)"; + + let expr = drasi_query_cypher::parse_expression(expr).unwrap(); + + let function_registry = Arc::new(FunctionRegistry::new()); + let ari = Arc::new(InMemoryResultIndex::new()); + let evaluator = ExpressionEvaluator::new(function_registry.clone(), ari.clone()); + + let mut variables = QueryVariables::new(); + + let sensor_val_version_list = vec![ + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(11)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(86)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(3)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(121)), + ); + map + }), + VariableValue::Object({ + let mut map = BTreeMap::new(); + map.insert( + "value".to_string(), + VariableValue::Integer(Integer::from(-45)), + ); + map + }), + ]; + variables.insert( + "param1".to_string().into(), + VariableValue::List(sensor_val_version_list), + ); + let context = + ExpressionEvaluationContext::new(&variables, Arc::new(InstantQueryClock::new(0, 0))); + + assert_eq!( + evaluator + .evaluate_expression(&context, &expr) + .await + .unwrap(), + VariableValue::Integer(0.into()) + ); +} diff --git a/core/src/evaluation/parts/tests/multi_part.rs b/core/src/evaluation/parts/tests/multi_part.rs index c956570..cb62b16 100644 --- a/core/src/evaluation/parts/tests/multi_part.rs +++ b/core/src/evaluation/parts/tests/multi_part.rs @@ -413,7 +413,7 @@ async fn aggregating_part_to_aggregating_part_add_solution() { " MATCH (a) WHERE a.Value1 < 10 - WITH a.Name, a.Category, sum(a.Value1) as my_sum + WITH a.Name, sum(a.Value1) as my_sum, a.Category RETURN Category, avg(my_sum) as my_avg ", );