use vibesql_ast::Expression;
use vibesql_storage::Row;
use vibesql_types::SqlValue;
use super::*;
fn make_test_rows(values: Vec<i64>) -> Vec<Row> {
values.into_iter().map(|v| Row::new(vec![SqlValue::Integer(v)])).collect()
}
fn simple_eval(expr: &Expression, row: &Row) -> Result<SqlValue, String> {
match expr {
Expression::Literal(val) => Ok(val.clone()),
Expression::ColumnRef(col_id) => {
let col_idx: usize = col_id
.column_canonical()
.parse()
.map_err(|e| format!("Invalid column index: {}", e))?;
row.get(col_idx)
.cloned()
.ok_or_else(|| format!("Column index {} out of bounds", col_idx))
}
_ => Err("Unsupported expression in test".to_string()),
}
}
#[test]
fn test_lag_default_offset() {
let partition = Partition::new(make_test_rows(vec![10, 20, 30, 40, 50]));
let value_expr = Expression::ColumnRef(vibesql_ast::ColumnIdentifier::simple("0", false));
let result = evaluate_lag(&partition, 0, &value_expr, None, None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Null);
let result = evaluate_lag(&partition, 1, &value_expr, None, None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(10));
let result = evaluate_lag(&partition, 2, &value_expr, None, None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(20));
let result = evaluate_lag(&partition, 4, &value_expr, None, None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(40));
}
#[test]
fn test_lag_custom_offset() {
let partition = Partition::new(make_test_rows(vec![10, 20, 30, 40, 50]));
let value_expr = Expression::ColumnRef(vibesql_ast::ColumnIdentifier::simple("0", false));
let result = evaluate_lag(&partition, 0, &value_expr, Some(2), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Null);
let result = evaluate_lag(&partition, 1, &value_expr, Some(2), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Null);
let result = evaluate_lag(&partition, 2, &value_expr, Some(2), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(10));
let result = evaluate_lag(&partition, 3, &value_expr, Some(2), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(20));
let result = evaluate_lag(&partition, 4, &value_expr, Some(2), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(30));
}
#[test]
fn test_lag_with_default_value() {
let partition = Partition::new(make_test_rows(vec![10, 20, 30]));
let value_expr = Expression::ColumnRef(vibesql_ast::ColumnIdentifier::simple("0", false));
let default_expr = Expression::Literal(SqlValue::Integer(0));
let result =
evaluate_lag(&partition, 0, &value_expr, None, Some(&default_expr), simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(0));
let result =
evaluate_lag(&partition, 1, &value_expr, None, Some(&default_expr), simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(10));
let result =
evaluate_lag(&partition, 2, &value_expr, None, Some(&default_expr), simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(20));
}
#[test]
fn test_lag_offset_beyond_partition_start() {
let partition = Partition::new(make_test_rows(vec![10, 20, 30]));
let value_expr = Expression::ColumnRef(vibesql_ast::ColumnIdentifier::simple("0", false));
let result = evaluate_lag(&partition, 2, &value_expr, Some(100), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Null);
let default_expr = Expression::Literal(SqlValue::Integer(-1));
let result =
evaluate_lag(&partition, 2, &value_expr, Some(100), Some(&default_expr), simple_eval)
.unwrap();
assert_eq!(result, SqlValue::Integer(-1));
}
#[test]
fn test_lead_default_offset() {
let partition = Partition::new(make_test_rows(vec![10, 20, 30, 40, 50]));
let value_expr = Expression::ColumnRef(vibesql_ast::ColumnIdentifier::simple("0", false));
let result = evaluate_lead(&partition, 0, &value_expr, None, None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(20));
let result = evaluate_lead(&partition, 1, &value_expr, None, None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(30));
let result = evaluate_lead(&partition, 3, &value_expr, None, None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(50));
let result = evaluate_lead(&partition, 4, &value_expr, None, None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Null);
}
#[test]
fn test_lead_custom_offset() {
let partition = Partition::new(make_test_rows(vec![10, 20, 30, 40, 50]));
let value_expr = Expression::ColumnRef(vibesql_ast::ColumnIdentifier::simple("0", false));
let result = evaluate_lead(&partition, 0, &value_expr, Some(2), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(30));
let result = evaluate_lead(&partition, 1, &value_expr, Some(2), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(40));
let result = evaluate_lead(&partition, 2, &value_expr, Some(2), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(50));
let result = evaluate_lead(&partition, 3, &value_expr, Some(2), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Null);
let result = evaluate_lead(&partition, 4, &value_expr, Some(2), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Null);
}
#[test]
fn test_lead_with_default_value() {
let partition = Partition::new(make_test_rows(vec![10, 20, 30]));
let value_expr = Expression::ColumnRef(vibesql_ast::ColumnIdentifier::simple("0", false));
let default_expr = Expression::Literal(SqlValue::Integer(999));
let result =
evaluate_lead(&partition, 0, &value_expr, None, Some(&default_expr), simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(20));
let result =
evaluate_lead(&partition, 1, &value_expr, None, Some(&default_expr), simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(30));
let result =
evaluate_lead(&partition, 2, &value_expr, None, Some(&default_expr), simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(999));
}
#[test]
fn test_lead_offset_beyond_partition_end() {
let partition = Partition::new(make_test_rows(vec![10, 20, 30]));
let value_expr = Expression::ColumnRef(vibesql_ast::ColumnIdentifier::simple("0", false));
let result = evaluate_lead(&partition, 0, &value_expr, Some(100), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Null);
let default_expr = Expression::Literal(SqlValue::Integer(-1));
let result =
evaluate_lead(&partition, 0, &value_expr, Some(100), Some(&default_expr), simple_eval)
.unwrap();
assert_eq!(result, SqlValue::Integer(-1));
}
#[test]
fn test_lag_lead_single_row_partition() {
let partition = Partition::new(make_test_rows(vec![42]));
let value_expr = Expression::ColumnRef(vibesql_ast::ColumnIdentifier::simple("0", false));
let result = evaluate_lag(&partition, 0, &value_expr, None, None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Null);
let result = evaluate_lead(&partition, 0, &value_expr, None, None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Null);
}
#[test]
fn test_lag_lead_with_zero_offset() {
let partition = Partition::new(make_test_rows(vec![10, 20, 30]));
let value_expr = Expression::ColumnRef(vibesql_ast::ColumnIdentifier::simple("0", false));
let result = evaluate_lag(&partition, 1, &value_expr, Some(0), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(20));
let result = evaluate_lead(&partition, 1, &value_expr, Some(0), None, simple_eval).unwrap();
assert_eq!(result, SqlValue::Integer(20));
}
#[test]
fn test_lag_negative_offset_becomes_lead() {
let partition = Partition::new(make_test_rows(vec![10, 20, 30]));
let value_expr = Expression::ColumnRef(vibesql_ast::ColumnIdentifier::simple("0", false));
let result = evaluate_lag(&partition, 1, &value_expr, Some(-1), None, simple_eval);
assert!(result.is_ok());
assert_eq!(result.unwrap(), SqlValue::Integer(30));
}
#[test]
fn test_lead_negative_offset_becomes_lag() {
let partition = Partition::new(make_test_rows(vec![10, 20, 30]));
let value_expr = Expression::ColumnRef(vibesql_ast::ColumnIdentifier::simple("0", false));
let result = evaluate_lead(&partition, 1, &value_expr, Some(-1), None, simple_eval);
assert!(result.is_ok());
assert_eq!(result.unwrap(), SqlValue::Integer(10));
}