drizzle 0.1.7

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

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

// Test table with UUID as TEXT column
#[SQLiteTable]
struct UuidTextTest {
    #[column(PRIMARY)]
    id: i32,
    #[column(text)] // UUID stored as TEXT (override from default BLOB)
    uuid_field: Uuid,
    name: String,
}

// Test table with UUID as BLOB column
#[SQLiteTable]
struct UuidBlobTest {
    #[column(PRIMARY)]
    id: i32,
    // UUID stored as BLOB (this is the default inference)
    uuid_field: Uuid,
    name: String,
}

// Test table with UUID TEXT column using default_fn
#[SQLiteTable]
struct UuidTextDefault {
    #[column(PRIMARY)]
    id: i32,
    #[column(text, DEFAULT_FN = Uuid::new_v4)] // UUID stored as TEXT with auto-generation
    uuid_field: Uuid,
    name: String,
}

// Test table with UUID BLOB column using default_fn
#[SQLiteTable]
struct UuidBlobDefault {
    #[column(PRIMARY)]
    id: i32,
    #[column(DEFAULT_FN = Uuid::new_v4)] // UUID stored as BLOB with auto-generation
    uuid_field: Uuid,
    name: String,
}

#[derive(SQLiteSchema)]
struct UuidTextSchema {
    uuid_text_test: UuidTextTest,
}

#[derive(SQLiteSchema)]
struct UuidBlobSchema {
    uuid_blob_test: UuidBlobTest,
}

#[derive(SQLiteSchema)]
struct UuidTextDefaultSchema {
    uuid_text_default: UuidTextDefault,
}

#[derive(SQLiteSchema)]
struct UuidBlobDefaultSchema {
    uuid_blob_default: UuidBlobDefault,
}

#[drizzle::test]
fn test_uuid_text_storage(db: &mut TestDb<UuidTextSchema>) {
    let table = schema.uuid_text_test;

    // Generate test UUID
    let test_uuid = Uuid::new_v4();
    let data = InsertUuidTextTest::new(test_uuid, "text storage test");

    // Insert data
    db.insert(table).values([data]).execute();

    // Query back the data using Drizzle
    let results: Vec<SelectUuidTextTest> = db
        .select((table.id, table.uuid_field, table.name))
        .from(table)
        .r#where(eq(table.name, "text storage test"))
        .all();

    assert_eq!(results.len(), 1);
    assert_eq!(results[0].uuid_field, test_uuid);
    assert_eq!(results[0].name, "text storage test");

    #[derive(SQLiteFromRow, Debug)]
    struct ReturnResult(String);
    // Verify it's stored as TEXT in the database
    let result: ReturnResult = db
        .select(r#typeof(table.uuid_field).alias("uuid_type"))
        .from(table)
        .r#where(eq(table.id, 1))
        .get();

    assert_eq!(result.0, "text");
}

#[drizzle::test]
fn test_uuid_blob_storage(db: &mut TestDb<UuidBlobSchema>) {
    let table = schema.uuid_blob_test;

    // Generate test UUID
    let test_uuid = Uuid::new_v4();
    let data = InsertUuidBlobTest::new(test_uuid, "blob storage test");

    // Insert data
    db.insert(table).values([data]).execute();

    // Query back the data using Drizzle
    let results: Vec<SelectUuidBlobTest> = db
        .select((table.id, table.uuid_field, table.name))
        .from(table)
        .r#where(eq(table.name, "blob storage test"))
        .all();

    assert_eq!(results.len(), 1);
    assert_eq!(results[0].uuid_field, test_uuid);
    assert_eq!(results[0].name, "blob storage test");

    #[derive(SQLiteFromRow, Debug)]
    struct ReturnResult(String);
    // Verify it's stored as BLOB in the database
    let result: ReturnResult = db
        .select(r#typeof(table.uuid_field).alias("uuid_type"))
        .from(table)
        .r#where(eq(table.id, 1))
        .get();

    assert_eq!(result.0, "blob");
}

#[drizzle::test]
fn test_uuid_text_vs_blob_roundtrip_text(db: &mut TestDb<UuidTextSchema>) {
    // Test TEXT storage
    let test_uuid = Uuid::new_v4();
    let table = schema.uuid_text_test;

    let data = InsertUuidTextTest::new(test_uuid, "roundtrip test");
    db.insert(table).values([data]).execute();

    let results: Vec<SelectUuidTextTest> = db
        .select((table.id, table.uuid_field, table.name))
        .from(table)
        .all();
    assert_eq!(results[0].uuid_field, test_uuid);
}

#[drizzle::test]
fn test_uuid_text_vs_blob_roundtrip_blob(db: &mut TestDb<UuidBlobSchema>) {
    // Test BLOB storage
    let test_uuid = Uuid::new_v4();
    let table = schema.uuid_blob_test;

    let data = InsertUuidBlobTest::new(test_uuid, "roundtrip test");
    db.insert(table).values([data]).execute();

    let results: Vec<SelectUuidBlobTest> = db
        .select((table.id, table.uuid_field, table.name))
        .from(table)
        .all();
    assert_eq!(results[0].uuid_field, test_uuid);
}

#[drizzle::test]
fn test_uuid_text_default_fn(db: &mut TestDb<UuidTextDefaultSchema>) {
    let table = schema.uuid_text_default;

    // Insert without specifying UUID - should use default_fn
    let data = InsertUuidTextDefault::new("auto-generated text uuid");
    db.insert(table).values([data]).execute();

    // Query back the data
    let results: Vec<SelectUuidTextDefault> = db
        .select((table.id, table.uuid_field, table.name))
        .from(table)
        .all();

    assert_eq!(results.len(), 1);
    assert_eq!(results[0].name, "auto-generated text uuid");

    // Verify UUID was generated (not nil)
    assert_ne!(results[0].uuid_field, Uuid::nil());

    #[derive(SQLiteFromRow, Debug)]
    struct ReturnResult(String);
    // Verify it's stored as TEXT
    let result: ReturnResult = db
        .select(r#typeof(table.uuid_field).alias("uuid_type"))
        .from(table)
        .r#where(eq(table.id, 1))
        .get();

    assert_eq!(result.0, "text");
}

#[drizzle::test]
fn test_uuid_blob_default_fn(db: &mut TestDb<UuidBlobDefaultSchema>) {
    let table = schema.uuid_blob_default;

    // Insert without specifying UUID - should use default_fn
    let data = InsertUuidBlobDefault::new("auto-generated blob uuid");
    db.insert(table).values([data]).execute();

    // Query back the data
    let results: Vec<SelectUuidBlobDefault> = db
        .select((table.id, table.uuid_field, table.name))
        .from(table)
        .all();

    assert_eq!(results.len(), 1);
    assert_eq!(results[0].name, "auto-generated blob uuid");

    // Verify UUID was generated (not nil)
    assert_ne!(results[0].uuid_field, Uuid::nil());

    #[derive(SQLiteFromRow, Debug)]
    struct ReturnResult(String);
    // Verify it's stored as BLOB
    let result: ReturnResult = db
        .select(r#typeof(table.uuid_field).alias("uuid_type"))
        .from(table)
        .r#where(eq(table.id, 1))
        .get();

    assert_eq!(result.0, "blob");
}

#[drizzle::test]
fn test_uuid_text_default_fn_uniqueness(db: &mut TestDb<UuidTextDefaultSchema>) {
    // Test TEXT default_fn generates unique UUIDs
    let table = schema.uuid_text_default;

    let data1 = InsertUuidTextDefault::new("first");
    let data2 = InsertUuidTextDefault::new("second");

    db.insert(table).values([data1, data2]).execute();

    let results: Vec<SelectUuidTextDefault> = db
        .select((table.id, table.uuid_field, table.name))
        .from(table)
        .all();
    assert_eq!(results.len(), 2);

    // Verify UUIDs are different
    assert_ne!(results[0].uuid_field, results[1].uuid_field);
    assert_ne!(results[0].uuid_field, Uuid::nil());
    assert_ne!(results[1].uuid_field, Uuid::nil());
}

#[drizzle::test]
fn test_uuid_blob_default_fn_uniqueness(db: &mut TestDb<UuidBlobDefaultSchema>) {
    // Test BLOB default_fn generates unique UUIDs
    let table = schema.uuid_blob_default;

    let data1 = InsertUuidBlobDefault::new("first");
    let data2 = InsertUuidBlobDefault::new("second");

    db.insert(table).values([data1, data2]).execute();

    let results: Vec<SelectUuidBlobDefault> = db
        .select((table.id, table.uuid_field, table.name))
        .from(table)
        .all();
    assert_eq!(results.len(), 2);

    // Verify UUIDs are different
    assert_ne!(results[0].uuid_field, results[1].uuid_field);
    assert_ne!(results[0].uuid_field, Uuid::nil());
    assert_ne!(results[1].uuid_field, Uuid::nil());
}