use sql_cli::data::data_view::DataView;
use sql_cli::data::datatable::{DataColumn, DataRow, DataTable, DataValue};
use sql_cli::sql::parser::ast::{ColumnRef, OrderByItem, QuoteStyle, SqlExpression};
use sql_cli::sql::recursive_parser::SortDirection;
use sql_cli::sql::window_context::WindowContext;
use std::sync::Arc;
#[test]
fn test_window_context_single_partition() {
let mut table = DataTable::new("test");
table.add_column(DataColumn::new("id"));
table.add_column(DataColumn::new("value"));
for i in 1..=5 {
table
.add_row(DataRow::new(vec![
DataValue::Integer(i),
DataValue::Integer(i * 10),
]))
.unwrap();
}
let view = DataView::new(Arc::new(table));
let context = WindowContext::new(
Arc::new(view),
vec![], vec![OrderByItem {
expr: SqlExpression::Column(ColumnRef {
name: "id".to_string(),
quote_style: QuoteStyle::None,
table_prefix: None,
}),
direction: SortDirection::Asc,
}],
)
.unwrap();
assert_eq!(
context.get_offset_value(0, -1, "value"),
None, );
assert_eq!(
context.get_offset_value(1, -1, "value"),
Some(DataValue::Integer(10)), );
assert_eq!(
context.get_offset_value(2, -1, "value"),
Some(DataValue::Integer(20)), );
assert_eq!(
context.get_offset_value(0, 1, "value"),
Some(DataValue::Integer(20)), );
assert_eq!(
context.get_offset_value(4, 1, "value"),
None, );
assert_eq!(context.get_row_number(0), 1);
assert_eq!(context.get_row_number(1), 2);
assert_eq!(context.get_row_number(4), 5);
}
#[test]
fn test_window_context_with_partitions() {
let mut table = DataTable::new("test");
table.add_column(DataColumn::new("category"));
table.add_column(DataColumn::new("id"));
table.add_column(DataColumn::new("value"));
let data = vec![
("A", 1, 100),
("A", 2, 200),
("A", 3, 300),
("B", 1, 10),
("B", 2, 20),
];
for (cat, id, val) in data {
table
.add_row(DataRow::new(vec![
DataValue::String(cat.to_string()),
DataValue::Integer(id),
DataValue::Integer(val),
]))
.unwrap();
}
let view = DataView::new(Arc::new(table));
let context = WindowContext::new(
Arc::new(view),
vec!["category".to_string()],
vec![OrderByItem {
expr: SqlExpression::Column(ColumnRef {
name: "id".to_string(),
quote_style: QuoteStyle::None,
table_prefix: None,
}),
direction: SortDirection::Asc,
}],
)
.unwrap();
assert_eq!(context.partition_count(), 2);
assert_eq!(context.get_row_number(0), 1); assert_eq!(context.get_row_number(1), 2); assert_eq!(context.get_row_number(3), 1); assert_eq!(context.get_row_number(4), 2);
assert_eq!(
context.get_offset_value(0, -1, "value"),
None, );
assert_eq!(
context.get_offset_value(1, -1, "value"),
Some(DataValue::Integer(100)), );
assert_eq!(
context.get_offset_value(3, -1, "value"),
None, );
assert_eq!(
context.get_first_value(1, "value"), Some(DataValue::Integer(100)), );
assert_eq!(
context.get_last_value(1, "value"), Some(DataValue::Integer(300)), );
assert_eq!(
context.get_first_value(4, "value"), Some(DataValue::Integer(10)), );
}
#[test]
fn test_window_context_order_by_desc() {
let mut table = DataTable::new("test");
table.add_column(DataColumn::new("value"));
let values = vec![30, 10, 20, 50, 40];
for v in values {
table
.add_row(DataRow::new(vec![DataValue::Integer(v)]))
.unwrap();
}
let view = DataView::new(Arc::new(table));
let context = WindowContext::new(
Arc::new(view),
vec![],
vec![OrderByItem {
expr: SqlExpression::Column(ColumnRef {
name: "value".to_string(),
quote_style: QuoteStyle::None,
table_prefix: None,
}),
direction: SortDirection::Desc,
}],
)
.unwrap();
assert_eq!(context.get_row_number(3), 1); assert_eq!(context.get_row_number(4), 2); assert_eq!(context.get_row_number(0), 3); assert_eq!(context.get_row_number(2), 4); assert_eq!(context.get_row_number(1), 5);
assert_eq!(
context.get_offset_value(4, -1, "value"), Some(DataValue::Integer(50)), );
assert_eq!(
context.get_offset_value(0, -1, "value"), Some(DataValue::Integer(40)), );
}