Execute projection with aggregate functions (returns single row)
(
&self,
expressions: &[ProjectionItem],
input_rows: Vec<Row>,
context: &mut ExecutionContext,
)
| 6054 | |
| 6055 | /// Execute projection with aggregate functions (returns single row) |
| 6056 | fn execute_aggregate_projection( |
| 6057 | &self, |
| 6058 | expressions: &[ProjectionItem], |
| 6059 | input_rows: Vec<Row>, |
| 6060 | context: &mut ExecutionContext, |
| 6061 | ) -> Result<Vec<Row>, ExecutionError> { |
| 6062 | let mut result_row = Row::new(); |
| 6063 | |
| 6064 | // Evaluate each projection expression with all input rows |
| 6065 | for proj_item in expressions { |
| 6066 | let value = if let Expression::FunctionCall(func_call) = &proj_item.expression { |
| 6067 | // Handle aggregate function |
| 6068 | let function = self.function_registry.get(&func_call.name).ok_or_else(|| { |
| 6069 | ExecutionError::UnsupportedOperator(format!( |
| 6070 | "Function not found: {}", |
| 6071 | func_call.name |
| 6072 | )) |
| 6073 | })?; |
| 6074 | |
| 6075 | // Evaluate arguments (currently COUNT has no arguments, but others might) |
| 6076 | let mut evaluated_args = Vec::new(); |
| 6077 | for arg in &func_call.arguments { |
| 6078 | // For arguments like AVERAGE(account.balance), we need to pass the full property path |
| 6079 | if let Expression::PropertyAccess(prop) = arg { |
| 6080 | // Pass the full property path (e.g., "account.balance", "account.id") |
| 6081 | let full_property = format!("{}.{}", prop.object, prop.property); |
| 6082 | evaluated_args.push(Value::String(full_property)); |
| 6083 | } else if let Expression::Variable(var) = arg { |
| 6084 | evaluated_args.push(Value::String(var.name.clone())); |
| 6085 | } else { |
| 6086 | // For other expression types, evaluate them using the existing context |
| 6087 | let value = self.evaluate_expression(arg, context)?; |
| 6088 | evaluated_args.push(value); |
| 6089 | } |
| 6090 | } |
| 6091 | |
| 6092 | // Create function context with all input rows and storage access |
| 6093 | let function_context = FunctionContext::with_storage( |
| 6094 | input_rows.clone(), |
| 6095 | HashMap::new(), |
| 6096 | evaluated_args, |
| 6097 | context.storage_manager.clone(), |
| 6098 | context.current_graph.clone(), |
| 6099 | context.get_current_graph_name(), |
| 6100 | ); |
| 6101 | |
| 6102 | // Execute the function |
| 6103 | function.execute(&function_context).map_err(|e| { |
| 6104 | ExecutionError::UnsupportedOperator(format!("Function execution error: {}", e)) |
| 6105 | })? |
| 6106 | } else { |
| 6107 | // Non-aggregate expression in aggregate context - this is usually invalid SQL |
| 6108 | // but for simplicity, we'll return null or error |
| 6109 | return Err(ExecutionError::ExpressionError( |
| 6110 | "Non-aggregate expressions not allowed with aggregate functions".to_string(), |
| 6111 | )); |
| 6112 | }; |
| 6113 |
no test coverage detected