use rustlite::{Column, Database, ExecutionContext, Row, Value};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("RustLite Aggregate Functions Demo");
println!("==================================\n");
let db = Database::in_memory()?;
println!("1. Simple COUNT - Total number of sales:");
println!(" SQL: SELECT COUNT(*) AS total_sales FROM sales\n");
let plan = db.prepare("SELECT COUNT(*) AS total_sales FROM sales")?;
let mut context = ExecutionContext::new();
context.data.insert(
"sales".to_string(),
vec![
create_sale(1, "Electronics", 1000),
create_sale(2, "Electronics", 1500),
create_sale(3, "Books", 200),
create_sale(4, "Books", 300),
create_sale(5, "Clothing", 400),
],
);
let results = db.execute_plan(&plan, context.clone())?;
print_results(&results);
println!();
println!("2. SUM - Total revenue:");
println!(" SQL: SELECT SUM(amount) AS total_revenue FROM sales\n");
let plan = db.prepare("SELECT SUM(amount) AS total_revenue FROM sales")?;
let results = db.execute_plan(&plan, context.clone())?;
print_results(&results);
println!();
println!("3. AVG - Average sale amount:");
println!(" SQL: SELECT AVG(amount) AS avg_sale FROM sales\n");
let plan = db.prepare("SELECT AVG(amount) AS avg_sale FROM sales")?;
let results = db.execute_plan(&plan, context.clone())?;
print_results(&results);
println!();
println!("4. MIN/MAX - Smallest and largest sales:");
println!(" SQL: SELECT MIN(amount) AS min_sale, MAX(amount) AS max_sale FROM sales\n");
let plan = db.prepare("SELECT MIN(amount) AS min_sale, MAX(amount) AS max_sale FROM sales")?;
let results = db.execute_plan(&plan, context.clone())?;
print_results(&results);
println!();
println!("5. GROUP BY - Total revenue by category:");
println!(" SQL: SELECT category, SUM(amount) AS revenue FROM sales GROUP BY category\n");
let plan =
db.prepare("SELECT category, SUM(amount) AS revenue FROM sales GROUP BY category")?;
let results = db.execute_plan(&plan, context.clone())?;
print_results(&results);
println!();
println!("6. GROUP BY - Average sale by category:");
println!(" SQL: SELECT category, AVG(amount) AS avg_sale FROM sales GROUP BY category\n");
let plan =
db.prepare("SELECT category, AVG(amount) AS avg_sale FROM sales GROUP BY category")?;
let results = db.execute_plan(&plan, context.clone())?;
print_results(&results);
println!();
println!("7. GROUP BY - Min and max sales by category:");
println!(" SQL: SELECT category, MIN(amount) AS min_sale, MAX(amount) AS max_sale FROM sales GROUP BY category\n");
let plan = db.prepare("SELECT category, MIN(amount) AS min_sale, MAX(amount) AS max_sale FROM sales GROUP BY category")?;
let results = db.execute_plan(&plan, context.clone())?;
print_results(&results);
println!();
println!("8. HAVING - Filter categories:");
println!(" SQL: SELECT category, SUM(amount) AS revenue FROM sales GROUP BY category HAVING category = 'Electronics'\n");
let plan = db.prepare("SELECT category, SUM(amount) AS revenue FROM sales GROUP BY category HAVING category = 'Electronics'")?;
let results = db.execute_plan(&plan, context)?;
print_results(&results);
println!();
println!("\nReal-World Use Case: Customer Order Analytics");
println!("=============================================\n");
let plan = db.prepare("SELECT customer_id, SUM(amount) AS total_spent, AVG(amount) AS avg_order FROM orders GROUP BY customer_id")?;
let mut context = ExecutionContext::new();
context.data.insert(
"orders".to_string(),
vec![
create_order(1001, 150),
create_order(1001, 200),
create_order(1001, 350),
create_order(1002, 500),
create_order(1002, 600),
create_order(1003, 100),
],
);
println!("Customer order statistics:");
println!("SQL: SELECT customer_id, SUM(amount) AS total_spent, AVG(amount) AS avg_order");
println!(" FROM orders GROUP BY customer_id\n");
let results = db.execute_plan(&plan, context)?;
print_results(&results);
Ok(())
}
fn create_sale(id: i64, category: &str, amount: i64) -> Row {
Row {
columns: vec![
Column {
name: "id".to_string(),
alias: None,
},
Column {
name: "category".to_string(),
alias: None,
},
Column {
name: "amount".to_string(),
alias: None,
},
],
values: vec![
Value::Integer(id),
Value::String(category.to_string()),
Value::Integer(amount),
],
}
}
fn create_order(customer_id: i64, amount: i64) -> Row {
Row {
columns: vec![
Column {
name: "customer_id".to_string(),
alias: None,
},
Column {
name: "amount".to_string(),
alias: None,
},
],
values: vec![Value::Integer(customer_id), Value::Integer(amount)],
}
}
fn print_results(results: &[Row]) {
if results.is_empty() {
println!(" (no results)");
return;
}
print!(" ");
for col in &results[0].columns {
print!("{:20}", col.name);
}
println!();
print!(" ");
for _ in &results[0].columns {
print!("{:20}", "--------------------");
}
println!();
for row in results {
print!(" ");
for value in &row.values {
let display = match value {
Value::Integer(i) => format!("{}", i),
Value::Float(f) => format!("{:.2}", f),
Value::String(s) => s.clone(),
Value::Boolean(b) => format!("{}", b),
Value::Null => "NULL".to_string(),
};
print!("{:20}", display);
}
println!();
}
}