use vibesql_ast::Expression;
use vibesql_types::SqlValue;
use super::{partitioning::Partition, utils::evaluate_default_value};
pub fn evaluate_lag<F>(
partition: &Partition,
current_row_idx: usize,
value_expr: &Expression,
offset: Option<i64>,
default: Option<&Expression>,
eval_fn: F,
) -> Result<SqlValue, String>
where
F: Fn(&Expression, &vibesql_storage::Row) -> Result<SqlValue, String>,
{
let offset_val = offset.unwrap_or(1);
if offset_val < 0 {
return evaluate_lead(
partition,
current_row_idx,
value_expr,
Some(-offset_val),
default,
eval_fn,
);
}
let target_idx = if offset_val as usize > current_row_idx {
return evaluate_default_value(default);
} else {
current_row_idx - offset_val as usize
};
if let Some(target_row) = partition.rows.get(target_idx) {
eval_fn(value_expr, target_row)
} else {
Ok(evaluate_default_value(default)?)
}
}
pub fn evaluate_lead<F>(
partition: &Partition,
current_row_idx: usize,
value_expr: &Expression,
offset: Option<i64>,
default: Option<&Expression>,
eval_fn: F,
) -> Result<SqlValue, String>
where
F: Fn(&Expression, &vibesql_storage::Row) -> Result<SqlValue, String>,
{
let offset_val = offset.unwrap_or(1);
if offset_val < 0 {
return evaluate_lag(
partition,
current_row_idx,
value_expr,
Some(-offset_val),
default,
eval_fn,
);
}
let target_idx = current_row_idx + offset_val as usize;
if target_idx >= partition.len() {
return evaluate_default_value(default);
}
if let Some(target_row) = partition.rows.get(target_idx) {
eval_fn(value_expr, target_row)
} else {
Ok(evaluate_default_value(default)?)
}
}