qail-pg 0.27.10

Rust PostgreSQL driver for typed AST queries with direct wire-protocol execution
Documentation
//! Battle test: QAIL queries against real PostgreSQL
//!
//! Run with: cargo run --example battle_test

use qail_core::prelude::{JoinKind, Operator, Qail, SortOrder, Value};
use qail_pg::driver::PgDriver;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("๐Ÿ”ฅ QAIL Deep Battle Test");
    println!("========================\n");

    let mut driver = PgDriver::connect("127.0.0.1", 5432, "orion", "qail_test_migration").await?;

    // =========== SETUP TEST DATA ===========
    println!("๏ฟฝ Setup Test Data");
    println!("------------------");

    // Clean slate
    let _ = driver.execute(&Qail::del("inquiries")).await;

    // Insert test data with various values
    for (name, email, service, status) in [
        ("Alice", "alice@test.com", "wedding", "new"),
        ("Bob", "bob@test.com", "corporate", "read"),
        ("Charlie", "charlie@test.com", "wedding", "new"),
        ("Diana", "diana@test.com", "birthday", "replied"),
        ("Eve", "eve@test.com", "wedding", "new"),
    ] {
        let insert = Qail::add("inquiries")
            .columns(["name", "email", "service", "status", "message"])
            .values([name, email, service, status, "Test message"]);
        driver.execute(&insert).await?;
    }
    println!("  โœ“ Inserted 5 test rows");

    // =========== BASIC SELECT TESTS ===========
    println!("\n๐Ÿ“– SELECT Tests - Basic");
    println!("------------------------");

    // SELECT *
    let select_all = Qail::get("inquiries").select_all();
    match driver.fetch_all(&select_all).await {
        Ok(rows) => println!("  โœ“ SELECT *: {} rows", rows.len()),
        Err(e) => println!("  โœ— SELECT *: {}", e),
    }

    // SELECT with multiple columns
    let select_cols = Qail::get("inquiries").columns(["id", "name", "email", "status"]);
    match driver.fetch_all(&select_cols).await {
        Ok(rows) => println!("  โœ“ SELECT multi-column: {} rows", rows.len()),
        Err(e) => println!("  โœ— SELECT multi-column: {}", e),
    }

    // =========== WHERE CLAUSE OPERATORS ===========
    println!("\n๏ฟฝ WHERE Operators");
    println!("------------------");

    // Equals
    let eq = Qail::get("inquiries")
        .columns(["name"])
        .filter("status", Operator::Eq, "new");
    match driver.fetch_all(&eq).await {
        Ok(rows) => println!("  โœ“ WHERE = : {} rows (expect 3)", rows.len()),
        Err(e) => println!("  โœ— WHERE = : {}", e),
    }

    // Not Equals
    let ne = Qail::get("inquiries")
        .columns(["name"])
        .filter("status", Operator::Ne, "new");
    match driver.fetch_all(&ne).await {
        Ok(rows) => println!("  โœ“ WHERE != : {} rows (expect 2)", rows.len()),
        Err(e) => println!("  โœ— WHERE != : {}", e),
    }

    // LIKE
    let like = Qail::get("inquiries")
        .columns(["name"])
        .filter("name", Operator::Like, "A%");
    match driver.fetch_all(&like).await {
        Ok(rows) => println!("  โœ“ WHERE LIKE: {} rows (expect 1: Alice)", rows.len()),
        Err(e) => println!("  โœ— WHERE LIKE: {}", e),
    }

    // ILIKE (case-insensitive)
    let ilike = Qail::get("inquiries")
        .columns(["name"])
        .filter("name", Operator::ILike, "%LI%");
    match driver.fetch_all(&ilike).await {
        Ok(rows) => println!("  โœ“ WHERE ILIKE: {} rows (Alice, Charlie)", rows.len()),
        Err(e) => println!("  โœ— WHERE ILIKE: {}", e),
    }

    // IN operator
    let in_op = Qail::get("inquiries").columns(["name"]).filter(
        "service",
        Operator::In,
        Value::Array(vec![
            Value::String("wedding".into()),
            Value::String("birthday".into()),
        ]),
    );
    match driver.fetch_all(&in_op).await {
        Ok(rows) => println!("  โœ“ WHERE IN: {} rows (expect 4)", rows.len()),
        Err(e) => println!("  โœ— WHERE IN: {}", e),
    }

    // IS NULL (test on optional field)
    let is_null = Qail::get("inquiries")
        .columns(["name"])
        .filter("phone", Operator::IsNull, "");
    match driver.fetch_all(&is_null).await {
        Ok(rows) => println!("  โœ“ WHERE IS NULL: {} rows", rows.len()),
        Err(e) => println!("  โœ— WHERE IS NULL: {}", e),
    }

    // =========== JOIN TESTS ===========
    println!("\n๐Ÿ”— JOIN Tests");
    println!("--------------");

    // LEFT JOIN (self-join for testing)
    let left_join = Qail::get("inquiries")
        .columns(["inquiries.id", "inquiries.name"])
        .join(
            JoinKind::Left,
            "inquiries AS i2",
            "inquiries.service",
            "i2.service",
        )
        .limit(5);
    match driver.fetch_all(&left_join).await {
        Ok(rows) => println!("  โœ“ LEFT JOIN: {} rows", rows.len()),
        Err(e) => println!("  โœ— LEFT JOIN: {}", e),
    }

    // =========== ORDER BY + LIMIT + OFFSET ===========
    println!("\n๐Ÿ“Š Pagination Tests");
    println!("-------------------");

    // ORDER BY DESC
    let order_desc = Qail::get("inquiries")
        .columns(["id", "name"])
        .order_by("id", SortOrder::Desc)
        .limit(3);
    match driver.fetch_all(&order_desc).await {
        Ok(rows) => println!("  โœ“ ORDER BY DESC LIMIT 3: {} rows", rows.len()),
        Err(e) => println!("  โœ— ORDER BY DESC: {}", e),
    }

    // LIMIT + OFFSET
    let paginated = Qail::get("inquiries")
        .columns(["id", "name"])
        .order_by("id", SortOrder::Asc)
        .limit(2)
        .offset(2);
    match driver.fetch_all(&paginated).await {
        Ok(rows) => println!("  โœ“ LIMIT 2 OFFSET 2: {} rows", rows.len()),
        Err(e) => println!("  โœ— LIMIT OFFSET: {}", e),
    }

    // =========== UPDATE TESTS ===========
    println!("\nโœ๏ธ  UPDATE Tests");
    println!("----------------");

    // Single column UPDATE
    let update_single = Qail::set("inquiries")
        .columns(["status"])
        .values(["archived"])
        .filter("name", Operator::Eq, "Eve");
    match driver.execute(&update_single).await {
        Ok(_) => println!("  โœ“ UPDATE single column: success"),
        Err(e) => println!("  โœ— UPDATE single column: {}", e),
    }

    // Multi-column UPDATE
    let update_multi = Qail::set("inquiries")
        .columns(["status", "message"])
        .values(["contacted", "Updated via QAIL"])
        .filter("name", Operator::Eq, "Diana");
    match driver.execute(&update_multi).await {
        Ok(_) => println!("  โœ“ UPDATE multi-column: success"),
        Err(e) => println!("  โœ— UPDATE multi-column: {}", e),
    }

    // UPDATE with LIKE in WHERE
    let update_like = Qail::set("inquiries")
        .columns(["status"])
        .values(["bulk_updated"])
        .filter("service", Operator::Eq, "wedding");
    match driver.execute(&update_like).await {
        Ok(_) => println!("  โœ“ UPDATE with complex WHERE: success"),
        Err(e) => println!("  โœ— UPDATE with complex WHERE: {}", e),
    }

    // =========== DELETE TESTS ===========
    println!("\n๐Ÿ—‘๏ธ  DELETE Tests");
    println!("----------------");

    // DELETE with specific filter
    let delete_one = Qail::del("inquiries").filter("name", Operator::Eq, "Bob");
    match driver.execute(&delete_one).await {
        Ok(_) => println!("  โœ“ DELETE specific row: success"),
        Err(e) => println!("  โœ— DELETE specific row: {}", e),
    }

    // Verify deletion
    let verify = Qail::get("inquiries").columns(["name"]);
    match driver.fetch_all(&verify).await {
        Ok(rows) => println!("  โœ“ Remaining rows: {} (expect 4)", rows.len()),
        Err(e) => println!("  โœ— Verify: {}", e),
    }

    // =========== DISTINCT TEST ===========
    println!("\n๐ŸŽฏ DISTINCT Test");
    println!("-----------------");

    // DISTINCT uses a field, set it directly
    let mut distinct = Qail::get("inquiries").columns(["service"]);
    distinct.distinct = true;
    match driver.fetch_all(&distinct).await {
        Ok(rows) => println!("  โœ“ SELECT DISTINCT: {} unique services", rows.len()),
        Err(e) => println!("  โœ— SELECT DISTINCT: {}", e),
    }

    // =========== CLEANUP ===========
    println!("\n๐Ÿงน Cleanup");
    println!("-----------");

    let cleanup = Qail::del("inquiries");
    match driver.execute(&cleanup).await {
        Ok(_) => println!("  โœ“ Cleanup: all test rows deleted"),
        Err(e) => println!("  โœ— Cleanup: {}", e),
    }

    println!("\nโœ… Deep battle test complete!");

    Ok(())
}