use sql_cli::data::data_view::DataView;
use sql_cli::data::datatable::{DataColumn, DataRow, DataTable, DataValue};
use sql_cli::data::query_engine::QueryEngine;
use std::sync::Arc;
fn get_value(view: &DataView, row_idx: usize, col_idx: usize) -> DataValue {
view.get_row(row_idx).unwrap().get(col_idx).unwrap().clone()
}
fn create_arithmetic_test_table() -> Arc<DataTable> {
let mut table = DataTable::new("arithmetic_test");
table.add_column(DataColumn::new("id"));
table.add_column(DataColumn::new("quantity"));
table.add_column(DataColumn::new("price"));
table.add_column(DataColumn::new("cost"));
table.add_column(DataColumn::new("discount"));
table
.add_row(DataRow::new(vec![
DataValue::Integer(1),
DataValue::Integer(10),
DataValue::Float(25.50),
DataValue::Float(20.00),
DataValue::Float(2.50),
]))
.unwrap();
table
.add_row(DataRow::new(vec![
DataValue::Integer(2),
DataValue::Integer(5),
DataValue::Float(100.00),
DataValue::Float(80.00),
DataValue::Float(10.00),
]))
.unwrap();
table
.add_row(DataRow::new(vec![
DataValue::Integer(3),
DataValue::Integer(3),
DataValue::Integer(15), DataValue::Integer(12), DataValue::Float(1.50),
]))
.unwrap();
table
.add_row(DataRow::new(vec![
DataValue::Integer(4),
DataValue::Integer(8),
DataValue::Float(45.75),
DataValue::Float(30.25),
DataValue::Float(5.00),
]))
.unwrap();
Arc::new(table)
}
#[test]
fn test_simple_multiplication() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let view = engine
.execute(
table.clone(),
"SELECT quantity * price as total FROM arithmetic_test",
)
.unwrap();
assert_eq!(view.row_count(), 4);
assert_eq!(view.column_count(), 1);
let columns = view.column_names();
assert_eq!(columns, vec!["total"]);
assert_eq!(get_value(&view, 0, 0), DataValue::Float(255.0));
assert_eq!(get_value(&view, 1, 0), DataValue::Float(500.0));
assert_eq!(get_value(&view, 2, 0), DataValue::Integer(45));
assert_eq!(get_value(&view, 3, 0), DataValue::Float(366.0));
}
#[test]
fn test_multiplication_with_literal() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let view = engine
.execute(
table.clone(),
"SELECT price * 2 as double_price FROM arithmetic_test",
)
.unwrap();
assert_eq!(view.row_count(), 4);
assert_eq!(view.column_count(), 1);
let row_data = view.get_row(0).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Float(51.0));
let row_data = view.get_row(2).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Integer(30));
}
#[test]
fn test_addition_and_subtraction() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let view = engine
.execute(
table.clone(),
"SELECT price + discount as total_price, price - cost as profit FROM arithmetic_test",
)
.unwrap();
assert_eq!(view.row_count(), 4);
assert_eq!(view.column_count(), 2);
let columns = view.column_names();
assert_eq!(columns, vec!["total_price", "profit"]);
let row_data = view.get_row(0).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Float(28.0));
assert_eq!(row_data.get(1).unwrap(), &DataValue::Float(5.50));
}
#[test]
fn test_division() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let view = engine
.execute(
table.clone(),
"SELECT price / quantity as unit_price FROM arithmetic_test",
)
.unwrap();
assert_eq!(view.row_count(), 4);
let row_data = view.get_row(0).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Float(2.55));
let row_data = view.get_row(1).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Float(20.0));
}
#[test]
fn test_complex_expression_with_precedence() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let view = engine
.execute(
table.clone(),
"SELECT (price - cost) * quantity / 2 as profit_per_two FROM arithmetic_test",
)
.unwrap();
assert_eq!(view.row_count(), 4);
let row_data = view.get_row(0).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Float(27.5));
}
#[test]
fn test_expression_with_multiple_operations() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let view = engine
.execute(
table.clone(),
"SELECT quantity * price / cost as efficiency FROM arithmetic_test",
)
.unwrap();
assert_eq!(view.row_count(), 4);
let row_data = view.get_row(0).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Float(12.75));
}
#[test]
fn test_mixed_columns_and_expressions() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let view = engine
.execute(
table.clone(),
"SELECT id, quantity, price, quantity * price as total FROM arithmetic_test",
)
.unwrap();
assert_eq!(view.row_count(), 4);
assert_eq!(view.column_count(), 4);
let columns = view.column_names();
assert_eq!(columns, vec!["id", "quantity", "price", "total"]);
let row_data = view.get_row(0).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Integer(1)); assert_eq!(row_data.get(1).unwrap(), &DataValue::Integer(10)); assert_eq!(row_data.get(2).unwrap(), &DataValue::Float(25.50)); assert_eq!(row_data.get(3).unwrap(), &DataValue::Float(255.0)); }
#[test]
fn test_type_coercion() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let view = engine
.execute(
table.clone(),
"SELECT quantity + 1.5 as adjusted_quantity FROM arithmetic_test",
)
.unwrap();
assert_eq!(view.row_count(), 4);
let row_data = view.get_row(0).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Float(11.5));
}
#[test]
fn test_division_by_zero_error() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let result = engine.execute(
table.clone(),
"SELECT price / 0 as invalid FROM arithmetic_test",
);
assert!(result.is_err());
let error_msg = result.unwrap_err().to_string();
assert!(error_msg.contains("division by zero") || error_msg.contains("Division by zero"));
}
#[test]
fn test_literal_only_expressions() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let view = engine
.execute(
table.clone(),
"SELECT 2 + 3 * 4 as math_result FROM arithmetic_test",
)
.unwrap();
assert_eq!(view.row_count(), 4);
let row_data = view.get_row(0).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Integer(14));
for i in 0..4 {
let row_data = view.get_row(i).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Integer(14));
}
}
#[test]
fn test_parentheses_precedence() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let view = engine
.execute(
table.clone(),
"SELECT (2 + 3) * 4 as paren_result FROM arithmetic_test",
)
.unwrap();
assert_eq!(view.row_count(), 4);
let row_data = view.get_row(0).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Integer(20));
}
#[test]
fn test_negative_numbers() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let view = engine
.execute(
table.clone(),
"SELECT price - cost - 50 as loss FROM arithmetic_test",
)
.unwrap();
assert_eq!(view.row_count(), 4);
let row_data = view.get_row(0).unwrap();
assert_eq!(row_data.get(0).unwrap(), &DataValue::Float(-44.50));
}
#[test]
#[ignore] fn test_where_clause_with_arithmetic() {
let table = create_arithmetic_test_table();
let engine = QueryEngine::new();
let view = engine
.execute(
table.clone(),
"SELECT id, quantity * price as total FROM arithmetic_test WHERE quantity * price > 200"
)
.unwrap();
assert_eq!(view.row_count(), 3);
}