mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-23 17:05:36 +01:00
support column comparisons in the filter operator
We currently only support column / literal comparisons in the filter operator. But with JOINs, comparisons are usually against two columns. Do the work to support it.
This commit is contained in:
@@ -1376,10 +1376,84 @@ impl DbspCompiler {
|
||||
match expr {
|
||||
LogicalExpr::BinaryExpr { left, op, right } => {
|
||||
// Extract column name and value for simple predicates
|
||||
if let (LogicalExpr::Column(col), LogicalExpr::Literal(val)) =
|
||||
// First check for column-to-column comparisons
|
||||
if let (LogicalExpr::Column(left_col), LogicalExpr::Column(right_col)) =
|
||||
(left.as_ref(), right.as_ref())
|
||||
{
|
||||
// Resolve column name to index using the schema
|
||||
// Resolve both column names to indices
|
||||
let left_idx = schema
|
||||
.columns
|
||||
.iter()
|
||||
.position(|c| c.name == left_col.name)
|
||||
.ok_or_else(|| {
|
||||
crate::LimboError::ParseError(format!(
|
||||
"Column '{}' not found in schema for filter",
|
||||
left_col.name
|
||||
))
|
||||
})?;
|
||||
|
||||
let right_idx = schema
|
||||
.columns
|
||||
.iter()
|
||||
.position(|c| c.name == right_col.name)
|
||||
.ok_or_else(|| {
|
||||
crate::LimboError::ParseError(format!(
|
||||
"Column '{}' not found in schema for filter",
|
||||
right_col.name
|
||||
))
|
||||
})?;
|
||||
|
||||
match op {
|
||||
BinaryOperator::Equals => Ok(FilterPredicate::ColumnEquals {
|
||||
left_idx,
|
||||
right_idx,
|
||||
}),
|
||||
BinaryOperator::NotEquals => Ok(FilterPredicate::ColumnNotEquals {
|
||||
left_idx,
|
||||
right_idx,
|
||||
}),
|
||||
BinaryOperator::Greater => Ok(FilterPredicate::ColumnGreaterThan {
|
||||
left_idx,
|
||||
right_idx,
|
||||
}),
|
||||
BinaryOperator::GreaterEquals => {
|
||||
Ok(FilterPredicate::ColumnGreaterThanOrEqual {
|
||||
left_idx,
|
||||
right_idx,
|
||||
})
|
||||
}
|
||||
BinaryOperator::Less => Ok(FilterPredicate::ColumnLessThan {
|
||||
left_idx,
|
||||
right_idx,
|
||||
}),
|
||||
BinaryOperator::LessEquals => Ok(FilterPredicate::ColumnLessThanOrEqual {
|
||||
left_idx,
|
||||
right_idx,
|
||||
}),
|
||||
BinaryOperator::And | BinaryOperator::Or => {
|
||||
// Handle logical operators recursively
|
||||
let left_pred = Self::compile_filter_predicate(left, schema)?;
|
||||
let right_pred = Self::compile_filter_predicate(right, schema)?;
|
||||
match op {
|
||||
BinaryOperator::And => Ok(FilterPredicate::And(
|
||||
Box::new(left_pred),
|
||||
Box::new(right_pred),
|
||||
)),
|
||||
BinaryOperator::Or => Ok(FilterPredicate::Or(
|
||||
Box::new(left_pred),
|
||||
Box::new(right_pred),
|
||||
)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
_ => Err(LimboError::ParseError(format!(
|
||||
"Unsupported operator in filter: {op:?}"
|
||||
))),
|
||||
}
|
||||
} else if let (LogicalExpr::Column(col), LogicalExpr::Literal(val)) =
|
||||
(left.as_ref(), right.as_ref())
|
||||
{
|
||||
// Column-to-literal comparisons
|
||||
let column_idx = schema
|
||||
.columns
|
||||
.iter()
|
||||
@@ -1455,7 +1529,7 @@ impl DbspCompiler {
|
||||
}
|
||||
} else {
|
||||
Err(LimboError::ParseError(
|
||||
"Filter predicate must be column op value".to_string(),
|
||||
"Filter predicate must be column op value or column op column".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,20 @@ pub enum FilterPredicate {
|
||||
LessThan { column_idx: usize, value: Value },
|
||||
/// Column <= value (using column index)
|
||||
LessThanOrEqual { column_idx: usize, value: Value },
|
||||
|
||||
/// Column = Column comparisons
|
||||
ColumnEquals { left_idx: usize, right_idx: usize },
|
||||
/// Column != Column comparisons
|
||||
ColumnNotEquals { left_idx: usize, right_idx: usize },
|
||||
/// Column > Column comparisons
|
||||
ColumnGreaterThan { left_idx: usize, right_idx: usize },
|
||||
/// Column >= Column comparisons
|
||||
ColumnGreaterThanOrEqual { left_idx: usize, right_idx: usize },
|
||||
/// Column < Column comparisons
|
||||
ColumnLessThan { left_idx: usize, right_idx: usize },
|
||||
/// Column <= Column comparisons
|
||||
ColumnLessThanOrEqual { left_idx: usize, right_idx: usize },
|
||||
|
||||
/// Logical AND of two predicates
|
||||
And(Box<FilterPredicate>, Box<FilterPredicate>),
|
||||
/// Logical OR of two predicates
|
||||
@@ -124,6 +138,82 @@ impl FilterOperator {
|
||||
let right_filter = FilterOperator::new((**right).clone());
|
||||
left_filter.evaluate_predicate(values) || right_filter.evaluate_predicate(values)
|
||||
}
|
||||
|
||||
// Column-to-column comparisons
|
||||
FilterPredicate::ColumnEquals {
|
||||
left_idx,
|
||||
right_idx,
|
||||
} => {
|
||||
if let (Some(left), Some(right)) = (values.get(*left_idx), values.get(*right_idx)) {
|
||||
return left == right;
|
||||
}
|
||||
false
|
||||
}
|
||||
FilterPredicate::ColumnNotEquals {
|
||||
left_idx,
|
||||
right_idx,
|
||||
} => {
|
||||
if let (Some(left), Some(right)) = (values.get(*left_idx), values.get(*right_idx)) {
|
||||
return left != right;
|
||||
}
|
||||
false
|
||||
}
|
||||
FilterPredicate::ColumnGreaterThan {
|
||||
left_idx,
|
||||
right_idx,
|
||||
} => {
|
||||
if let (Some(left), Some(right)) = (values.get(*left_idx), values.get(*right_idx)) {
|
||||
match (left, right) {
|
||||
(Value::Integer(a), Value::Integer(b)) => return a > b,
|
||||
(Value::Float(a), Value::Float(b)) => return a > b,
|
||||
(Value::Text(a), Value::Text(b)) => return a.as_str() > b.as_str(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
FilterPredicate::ColumnGreaterThanOrEqual {
|
||||
left_idx,
|
||||
right_idx,
|
||||
} => {
|
||||
if let (Some(left), Some(right)) = (values.get(*left_idx), values.get(*right_idx)) {
|
||||
match (left, right) {
|
||||
(Value::Integer(a), Value::Integer(b)) => return a >= b,
|
||||
(Value::Float(a), Value::Float(b)) => return a >= b,
|
||||
(Value::Text(a), Value::Text(b)) => return a.as_str() >= b.as_str(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
FilterPredicate::ColumnLessThan {
|
||||
left_idx,
|
||||
right_idx,
|
||||
} => {
|
||||
if let (Some(left), Some(right)) = (values.get(*left_idx), values.get(*right_idx)) {
|
||||
match (left, right) {
|
||||
(Value::Integer(a), Value::Integer(b)) => return a < b,
|
||||
(Value::Float(a), Value::Float(b)) => return a < b,
|
||||
(Value::Text(a), Value::Text(b)) => return a.as_str() < b.as_str(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
FilterPredicate::ColumnLessThanOrEqual {
|
||||
left_idx,
|
||||
right_idx,
|
||||
} => {
|
||||
if let (Some(left), Some(right)) = (values.get(*left_idx), values.get(*right_idx)) {
|
||||
match (left, right) {
|
||||
(Value::Integer(a), Value::Integer(b)) => return a <= b,
|
||||
(Value::Float(a), Value::Float(b)) => return a <= b,
|
||||
(Value::Text(a), Value::Text(b)) => return a.as_str() <= b.as_str(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user