drizzle 0.1.6

A type-safe SQL query builder for Rust
Documentation
#![cfg(any(feature = "rusqlite", feature = "turso", feature = "libsql"))]

use drizzle::core::expr::*;
use drizzle::sqlite::prelude::*;

// Test enums with different representations
#[derive(SQLiteEnum, PartialEq, Clone, Default, Debug)]
pub enum UserRole {
    #[default]
    Guest,
    Member,
    Admin,
}

#[derive(SQLiteEnum, Default, Debug, Clone, PartialEq)]
pub enum AccountStatus {
    Suspended = -1,
    #[default]
    Inactive = 3,
    Active,
}

// Table with enum fields using different column types
#[SQLiteTable]
struct UserAccount {
    #[column(PRIMARY, AUTOINCREMENT)]
    id: i64,
    name: String,
    #[column(ENUM)]
    role: UserRole,
    #[column(integer, ENUM)]
    status: AccountStatus,
}

#[derive(SQLiteSchema)]
pub struct Schema {
    user_account: UserAccount,
}

#[test]
fn test_enum() {
    // Test basic enum functionality works
    let role = UserRole::Admin;
    let status = AccountStatus::Active;

    // Test Display
    assert_eq!(format!("{}", role), "Admin");
    assert_eq!(format!("{}", status), "Active");

    // Test FromStr
    assert_eq!("Member".parse::<UserRole>().unwrap(), UserRole::Member);
    assert_eq!(
        "Suspended".parse::<AccountStatus>().unwrap(),
        AccountStatus::Suspended
    );
}

#[test]
fn test_table_generation() {
    // Just test that the table compiles and has the expected structure
    let _table = UserAccount::new();

    // Test that we can create insert and update models
    let insert_model = InsertUserAccount::new("test", UserRole::Member, AccountStatus::Suspended);
    let update_model = UpdateUserAccount::default();

    // Test convenience methods work with enums
    let _insert_with_role = insert_model.with_role(UserRole::Member);
    let _update_with_status = update_model.with_status(AccountStatus::Suspended);

    // Basic smoke test - if this compiles, the From implementations were generated correctly
    let table_ref = &<UserAccount as drizzle::core::DrizzleTable>::TABLE_REF;
    assert!(!table_ref.columns.is_empty());
}

// Enum types work directly in FromRow for all drivers (rusqlite, libsql, turso)
// - rusqlite: Uses FromSql trait generated by SQLiteEnum
// - libsql/turso: Uses TryFrom<i64> and TryFrom<&str> generated by SQLiteEnum
#[allow(dead_code)]
#[derive(Debug, SQLiteFromRow)]
struct UserAccountResult {
    id: i64,
    name: String,
    role: UserRole,        // Direct enum type - works with TEXT storage
    status: AccountStatus, // Direct enum type - works with INTEGER storage
}

#[drizzle::test]
fn test_enum_database_roundtrip(db: &mut TestDb<Schema>) {
    let Schema { user_account } = schema;

    // Insert test data with different enum values
    let test_users = vec![
        InsertUserAccount::new("guest_user", UserRole::Guest, AccountStatus::Inactive),
        InsertUserAccount::new("member_user", UserRole::Member, AccountStatus::Active),
        InsertUserAccount::new("admin_user", UserRole::Admin, AccountStatus::Suspended),
    ];

    let inserted = db.insert(user_account).values(test_users).execute();
    assert_eq!(inserted, 3);

    // Select and verify the data
    let results: Vec<UserAccountResult> = db
        .select((
            user_account.id,
            user_account.name,
            user_account.role,
            user_account.status,
        ))
        .from(user_account)
        .all();

    assert_eq!(results.len(), 3);

    // Verify guest user - enum types work for all drivers
    let guest = results.iter().find(|u| u.name == "guest_user").unwrap();
    assert_eq!(guest.role, UserRole::Guest);
    assert_eq!(guest.status, AccountStatus::Inactive);

    // Verify member user
    let member = results.iter().find(|u| u.name == "member_user").unwrap();
    assert_eq!(member.role, UserRole::Member);
    assert_eq!(member.status, AccountStatus::Active);

    // Verify admin user
    let admin = results.iter().find(|u| u.name == "admin_user").unwrap();
    assert_eq!(admin.role, UserRole::Admin);
    assert_eq!(admin.status, AccountStatus::Suspended);

    // Test filtering by enum values
    let admin_users: Vec<UserAccountResult> = db
        .select((
            user_account.id,
            user_account.name,
            user_account.role,
            user_account.status,
        ))
        .from(user_account)
        .r#where(eq(UserAccount::role, UserRole::Admin))
        .all();

    assert_eq!(admin_users.len(), 1);
    assert_eq!(admin_users[0].name, "admin_user");

    // Test filtering by integer enum
    let suspended_users: Vec<UserAccountResult> = db
        .select((
            user_account.id,
            user_account.name,
            user_account.role,
            user_account.status,
        ))
        .from(user_account)
        .r#where(eq(UserAccount::status, AccountStatus::Suspended))
        .all();

    assert_eq!(suspended_users.len(), 1);
    assert_eq!(suspended_users[0].name, "admin_user");
}