use gluesql_core::store::Transaction;
#[cfg(feature = "sql")]
use gluesql_core::{error::Result, executor::Payload, prelude::Glue};
#[cfg(feature = "sql")]
use prollytree::sql::ProllyStorage;
#[cfg(feature = "sql")]
use tempfile::TempDir;
#[cfg(feature = "sql")]
#[tokio::main]
async fn main() -> Result<()> {
println!("🌟 ProllyTree SQL Example");
println!("========================\n");
let temp_dir = TempDir::new().map_err(|e| {
gluesql_core::error::Error::StorageMsg(format!("Failed to create temp dir: {}", e))
})?;
println!("📁 Using temporary directory: {:?}\n", temp_dir.path());
std::process::Command::new("git")
.arg("init")
.current_dir(temp_dir.path())
.output()
.map_err(|e| {
gluesql_core::error::Error::StorageMsg(format!("Failed to init git: {}", e))
})?;
let dataset_path = temp_dir.path().join("dataset");
std::fs::create_dir(&dataset_path).map_err(|e| {
gluesql_core::error::Error::StorageMsg(format!("Failed to create dataset dir: {}", e))
})?;
let storage = ProllyStorage::<32>::init(&dataset_path)?;
let mut glue = Glue::new(storage);
glue.storage.begin(false).await?;
println!("1. Creating tables...");
let create_users = r#"
CREATE TABLE users (
id INTEGER,
name TEXT,
email TEXT,
age INTEGER
)
"#;
let create_orders = r#"
CREATE TABLE orders (
id INTEGER,
user_id INTEGER,
product TEXT,
amount INTEGER,
order_date TEXT
)
"#;
glue.storage.commit().await?;
glue.execute(create_users).await?;
glue.execute(create_orders).await?;
println!(" ✓ Created users and orders tables\n");
println!("2. Inserting sample data...");
let insert_users = r#"
INSERT INTO users (id, name, email, age) VALUES
(1, 'Alice Johnson', 'alice@example.com', 30),
(2, 'Bob Smith', 'bob@example.com', 25),
(3, 'Charlie Brown', 'charlie@example.com', 35),
(4, 'Diana Ross', 'diana@example.com', 28)
"#;
let insert_orders = r#"
INSERT INTO orders (id, user_id, product, amount, order_date) VALUES
(1, 1, 'Laptop', 1200, '2024-01-15'),
(2, 1, 'Mouse', 25, '2024-01-16'),
(3, 2, 'Keyboard', 75, '2024-01-17'),
(4, 3, 'Monitor', 300, '2024-01-18'),
(5, 3, 'Webcam', 80, '2024-01-19'),
(6, 4, 'Headphones', 150, '2024-01-20')
"#;
glue.execute(insert_users).await?;
glue.execute(insert_orders).await?;
println!(" ✓ Inserted sample data\n");
glue.storage.commit().await?;
println!("3. Running SELECT queries...");
let select_all_users = "SELECT * FROM users";
let result = glue.execute(select_all_users).await?;
print_results("All users:", &result);
let select_young_users = "SELECT name, age FROM users WHERE age < 30";
let result = glue.execute(select_young_users).await?;
print_results("Users under 30:", &result);
println!("4. Running JOIN queries...");
let join_query = r#"
SELECT u.name, o.product, o.amount, o.order_date
FROM users u
JOIN orders o ON u.id = o.user_id
ORDER BY o.order_date
"#;
let result = glue.execute(join_query).await?;
print_results("User orders:", &result);
println!("5. Running aggregation queries...");
let user_totals = r#"
SELECT u.name, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name
ORDER BY u.name
"#;
let result = glue.execute(user_totals).await?;
print_results("User spending summary:", &result);
let product_stats = r#"
SELECT product, COUNT(*) as quantity, AVG(amount) as avg_price
FROM orders
GROUP BY product
HAVING COUNT(*) >= 1
ORDER BY avg_price DESC
"#;
let result = glue.execute(product_stats).await?;
print_results("Product statistics:", &result);
println!("6. Running UPDATE and DELETE operations...");
let update_age = "UPDATE users SET age = 31 WHERE name = 'Alice Johnson'";
let result = glue.execute(update_age).await?;
println!(" ✓ Updated Alice's age: {:?}", result);
let delete_order = "DELETE FROM orders WHERE product = 'Mouse'";
let result = glue.execute(delete_order).await?;
println!(" ✓ Deleted mouse order: {:?}", result);
let verify_query = "SELECT name, age FROM users WHERE name = 'Alice Johnson'";
let result = glue.execute(verify_query).await?;
print_results("Alice's updated info:", &result);
glue.storage.commit().await?;
println!("7. Running advanced queries...");
let multi_order_customers = r#"
SELECT u.name, u.email
FROM users u
WHERE u.id = 1 OR u.id = 3
"#;
let result = glue.execute(multi_order_customers).await?;
print_results("Customers with multiple orders:", &result);
println!("\n🎉 SQL example completed successfully!");
println!("This demonstrates how ProllyTree can serve as a backend for SQL queries");
println!("while maintaining its versioned, git-like capabilities.\n");
let kv_store = glue.storage.store();
match kv_store.log() {
Ok(history) => {
println!("Git history:");
for commit_info in history {
println!(" - Commit: {:?}", commit_info);
}
}
Err(e) => {
println!("Failed to get git history: {:?}", e);
}
}
println!("Git keys:");
if let Ok(keys) = kv_store.list_keys() {
for key in keys {
match String::from_utf8(key.clone()) {
Ok(key_str) => println!(" - Key: {}", key_str),
Err(_) => println!(" - Key: {:?}", key),
}
}
}
Ok(())
}
#[cfg(feature = "sql")]
fn print_results(title: &str, payloads: &Vec<Payload>) {
println!("\n 📊 {}", title);
for payload in payloads {
match payload {
Payload::Select { labels, rows } => {
if rows.is_empty() {
println!(" (No results)");
continue;
}
let header = labels.join(" | ");
println!(" {}", header);
println!(" {}", "-".repeat(header.len()));
for row in rows {
let row_strs: Vec<String> = row.iter().map(|v| format!("{:?}", v)).collect();
println!(" {}", row_strs.join(" | "));
}
}
Payload::Insert(count) => println!(" ✓ Inserted {} rows", count),
Payload::Update(count) => println!(" ✓ Updated {} rows", count),
Payload::Delete(count) => println!(" ✓ Deleted {} rows", count),
_ => println!(" ✓ Operation completed"),
}
}
}
#[cfg(not(feature = "sql"))]
fn main() {
println!("❌ This example requires the 'sql' feature to be enabled.");
println!(" Run with: cargo run --example sql_example --features sql");
}