linkrs_query/executor/streaming/
join_helpers.rs1use std::sync::Arc;
2
3use crate::executor::expression::evaluator::ExpressionEvaluator;
4use crate::executor::streaming::executor::ValueRowContext;
5use crate::executor::streaming::slot::{combine_layouts, SlotLayout};
6use linkrs_core::error::QueryError;
7use linkrs_core::types::expr::Expression;
8use linkrs_core::Value;
9
10pub fn evaluate_join_key(
12 row: &[Value],
13 layout: Arc<SlotLayout>,
14 key_expressions: &[Expression],
15) -> Result<Vec<Value>, QueryError> {
16 if key_expressions.is_empty() {
17 return Ok(Vec::new());
18 }
19 let mut key = Vec::with_capacity(key_expressions.len());
20 for expr in key_expressions {
21 let mut context = ValueRowContext::new(row.to_vec(), layout.clone());
22 let value = ExpressionEvaluator::evaluate(expr, &mut context)
23 .map_err(|e| QueryError::execution(format!("HashJoin key evaluation failed: {e}")))?;
24 key.push(value);
25 }
26 Ok(key)
27}
28
29pub fn evaluate_residual_condition(
31 condition: &Expression,
32 left_row: &[Value],
33 right_row: &[Value],
34 left_schema: &[String],
35 right_schema: &[String],
36) -> Result<bool, QueryError> {
37 let mut combined = left_row.to_vec();
38 combined.extend_from_slice(right_row);
39 let combined_layout = build_combined_layout_from_schemas(left_schema, right_schema);
40 let mut context = ValueRowContext::new(combined, combined_layout);
41 match ExpressionEvaluator::evaluate(condition, &mut context) {
42 Ok(Value::Bool(b)) => Ok(b),
43 Ok(Value::Null(_)) => Ok(false),
44 Ok(_) => Ok(true),
45 Err(e) => Err(QueryError::execution(format!(
46 "HashJoin condition evaluation failed: {e}"
47 ))),
48 }
49}
50
51pub fn build_combined_layout_from_schemas(
53 left_schema: &[String],
54 right_schema: &[String],
55) -> Arc<SlotLayout> {
56 let left_layout = Arc::new(SlotLayout::from_names(left_schema));
57 let right_layout = Arc::new(SlotLayout::from_names(right_schema));
58 Arc::new(combine_layouts(&left_layout, &right_layout))
59}