#[cfg(test)]
mod tests {
use crate::{AggFunc, ElastiCubeBuilder};
use arrow::array::{Float64Array, Int32Array, StringArray};
use arrow::datatypes::{DataType, Field, Schema};
use arrow::record_batch::RecordBatch;
use std::sync::Arc;
fn create_test_data() -> RecordBatch {
let schema = Arc::new(Schema::new(vec![
Field::new("region", DataType::Utf8, false),
Field::new("revenue", DataType::Float64, false),
Field::new("cost", DataType::Float64, false),
Field::new("quantity", DataType::Int32, false),
]));
let region = Arc::new(StringArray::from(vec!["North", "South", "East", "West"]));
let revenue = Arc::new(Float64Array::from(vec![1000.0, 1500.0, 1200.0, 1800.0]));
let cost = Arc::new(Float64Array::from(vec![600.0, 900.0, 700.0, 1100.0]));
let quantity = Arc::new(Int32Array::from(vec![10, 15, 12, 18]));
RecordBatch::try_new(
schema,
vec![region, revenue, cost, quantity],
)
.unwrap()
}
#[tokio::test]
async fn test_calculated_measure_in_select() {
let batch = create_test_data();
let cube = Arc::new(
ElastiCubeBuilder::new("sales")
.add_dimension("region", DataType::Utf8)
.unwrap()
.add_measure("revenue", DataType::Float64, AggFunc::Sum)
.unwrap()
.add_measure("cost", DataType::Float64, AggFunc::Sum)
.unwrap()
.add_calculated_measure(
"profit",
"revenue - cost",
DataType::Float64,
AggFunc::Sum,
)
.unwrap()
.with_data(vec![batch])
.unwrap()
.build()
.unwrap(),
);
let query_builder = cube.clone().query().unwrap();
let sql = query_builder.select(&["region", "SUM(profit) as total_profit"])
.group_by(&["region"]);
let result = sql.execute().await.unwrap();
assert!(result.row_count() > 0, "Should have results");
}
#[tokio::test]
async fn test_virtual_dimension_in_select() {
use arrow::array::Date32Array;
let schema = Arc::new(Schema::new(vec![
Field::new("sale_date", DataType::Date32, false),
Field::new("amount", DataType::Float64, false),
]));
let dates = Arc::new(Date32Array::from(vec![
19000, 19100, 19365, 19500, ]));
let amounts = Arc::new(Float64Array::from(vec![100.0, 150.0, 200.0, 250.0]));
let batch =
RecordBatch::try_new(schema, vec![dates, amounts]).unwrap();
let cube = Arc::new(
ElastiCubeBuilder::new("sales")
.add_dimension("sale_date", DataType::Date32)
.unwrap()
.add_measure("amount", DataType::Float64, AggFunc::Sum)
.unwrap()
.add_virtual_dimension(
"year",
"EXTRACT(YEAR FROM sale_date)",
DataType::Int32,
)
.unwrap()
.with_data(vec![batch])
.unwrap()
.build()
.unwrap(),
);
let result = cube
.clone()
.query()
.unwrap()
.select(&["year", "SUM(amount) as total"])
.group_by(&["year"])
.execute()
.await
.unwrap();
assert!(result.row_count() > 0, "Should have results");
}
#[tokio::test]
async fn test_calculated_measure_in_filter() {
let batch = create_test_data();
let cube = Arc::new(
ElastiCubeBuilder::new("sales")
.add_dimension("region", DataType::Utf8)
.unwrap()
.add_measure("revenue", DataType::Float64, AggFunc::Sum)
.unwrap()
.add_measure("cost", DataType::Float64, AggFunc::Sum)
.unwrap()
.add_calculated_measure(
"profit",
"revenue - cost",
DataType::Float64,
AggFunc::Sum,
)
.unwrap()
.with_data(vec![batch])
.unwrap()
.build()
.unwrap(),
);
let result = cube
.clone()
.query()
.unwrap()
.select(&["region", "profit"])
.filter("profit > 550") .execute()
.await
.unwrap();
assert!(result.row_count() > 0, "Should have results");
assert!(result.row_count() == 2, "Should have exactly 2 rows (South and West)");
}
#[tokio::test]
async fn test_nested_calculated_measures() {
let batch = create_test_data();
let cube = Arc::new(
ElastiCubeBuilder::new("sales")
.add_dimension("region", DataType::Utf8)
.unwrap()
.add_measure("revenue", DataType::Float64, AggFunc::Sum)
.unwrap()
.add_measure("cost", DataType::Float64, AggFunc::Sum)
.unwrap()
.add_calculated_measure(
"profit",
"revenue - cost",
DataType::Float64,
AggFunc::Sum,
)
.unwrap()
.add_calculated_measure(
"margin",
"(profit / revenue) * 100",
DataType::Float64,
AggFunc::Avg,
)
.unwrap()
.with_data(vec![batch])
.unwrap()
.build()
.unwrap(),
);
let result = cube
.clone()
.query()
.unwrap()
.select(&["region", "margin"])
.execute()
.await
.unwrap();
assert_eq!(result.row_count(), 4, "Should have all rows");
}
#[tokio::test]
async fn test_multiple_calculated_fields_in_query() {
let batch = create_test_data();
let cube = Arc::new(
ElastiCubeBuilder::new("sales")
.add_dimension("region", DataType::Utf8)
.unwrap()
.add_measure("revenue", DataType::Float64, AggFunc::Sum)
.unwrap()
.add_measure("cost", DataType::Float64, AggFunc::Sum)
.unwrap()
.add_measure("quantity", DataType::Int32, AggFunc::Sum)
.unwrap()
.add_calculated_measure(
"profit",
"revenue - cost",
DataType::Float64,
AggFunc::Sum,
)
.unwrap()
.add_calculated_measure(
"avg_unit_price",
"revenue / quantity",
DataType::Float64,
AggFunc::Avg,
)
.unwrap()
.with_data(vec![batch])
.unwrap()
.build()
.unwrap(),
);
let result = cube
.clone()
.query()
.unwrap()
.select(&[
"region",
"SUM(profit) as total_profit",
"AVG(avg_unit_price) as avg_price",
])
.group_by(&["region"])
.order_by(&["total_profit DESC"])
.execute()
.await
.unwrap();
assert_eq!(result.row_count(), 4, "Should have all regions");
}
}