drizzle 0.1.10

A type-safe SQL query builder for Rust
Documentation
#![cfg(any(feature = "rusqlite", feature = "turso", feature = "libsql"))]
#[cfg(feature = "uuid")]
use crate::common::schema::sqlite::Role;
#[cfg(feature = "uuid")]
use crate::common::schema::sqlite::{Complex, InsertComplex, InsertPost, Post};
use crate::common::schema::sqlite::{InsertSimple, Simple};
use drizzle::core::expr::*;
use drizzle::sqlite::prelude::*;

use crate::common::schema::sqlite::SimpleSchema;
#[cfg(feature = "uuid")]
use crate::common::schema::sqlite::{ComplexPostSchema, ComplexSchema};

#[allow(dead_code)]
#[derive(SQLiteFromRow, Debug)]
struct SimpleResult {
    id: i32,
    name: String,
}

#[cfg(feature = "uuid")]
#[derive(SQLiteFromRow, Debug)]
struct JoinResult {
    user_name: String,
    post_title: String,
}

#[cfg(feature = "uuid")]
#[derive(SQLiteFromRow, Debug)]
struct NamePair {
    name1: String,
    name2: String,
}

tag!(AliasS, "s");
tag!(AliasSimple, "s_alias");

#[cfg(feature = "uuid")]
tag!(AliasC1, "c1");
#[cfg(feature = "uuid")]
tag!(AliasC2, "c2");
#[cfg(feature = "uuid")]
tag!(AliasU, "u");

#[cfg(feature = "uuid")]
struct AliasP;
#[cfg(feature = "uuid")]
impl drizzle::core::Tag for AliasP {
    const NAME: &'static str = "p";
}

#[drizzle::test]
fn basic_table_alias(db: &mut TestDb<SimpleSchema>) {
    let SimpleSchema { simple } = schema;

    // Insert test data
    let test_data = vec![
        InsertSimple::new("alice"),
        InsertSimple::new("bob"),
        InsertSimple::new("charlie"),
    ];

    db.insert(simple).values(test_data).execute();

    // Test basic table alias
    let s = Simple::alias::<AliasS>();
    let stmt = db
        .select(SimpleResult::Select)
        .from(s)
        .r#where(eq(s.name, "bob"));
    let results: Vec<SimpleResult> = stmt.all();

    assert_eq!(results.len(), 1);
    assert_eq!(results[0].name, "bob");
}

#[drizzle::test]
fn table_alias_with_conditions(db: &mut TestDb<SimpleSchema>) {
    let SimpleSchema { simple } = schema;

    // Insert test data
    let test_data = vec![
        InsertSimple::new("test1"),
        InsertSimple::new("test2"),
        InsertSimple::new("test3"),
    ];

    db.insert(simple).values(test_data).execute();

    // Test alias with WHERE conditions
    let s_alias = Simple::alias::<AliasSimple>();
    let stmt = db
        .select((s_alias.id, s_alias.name))
        .from(s_alias)
        .r#where(and(gt(s_alias.id, 1), neq(s_alias.name, "test3")));
    let results: Vec<SimpleResult> = stmt.all();

    assert_eq!(results.len(), 1);
    assert_eq!(results[0].name, "test2");
}

#[cfg(feature = "uuid")]
#[drizzle::test]
fn self_join_with_aliases(db: &mut TestDb<ComplexSchema>) {
    let ComplexSchema { complex, .. } = schema;

    // Insert test data with same email domain
    let test_data = vec![
        InsertComplex::new("user1", true, Role::User)
            .with_id(uuid::Uuid::new_v4())
            .with_email("test@example.com"),
        InsertComplex::new("user2", true, Role::User)
            .with_id(uuid::Uuid::new_v4())
            .with_email("test@example.com"),
        InsertComplex::new("user3", true, Role::User)
            .with_id(uuid::Uuid::new_v4())
            .with_email("other@domain.com"),
    ];

    db.insert(complex).values(test_data).execute();

    // Self-join using aliases to find users with same email
    let c1 = Complex::alias::<AliasC1>();
    let c2 = Complex::alias::<AliasC2>();

    let stmt = db
        .select((c1.name.alias("name1"), c2.name.alias("name2")))
        .from(c1)
        .inner_join((c2, eq(c1.email, c2.email)))
        .r#where(neq(c1.id, c2.id));
    let results: Vec<NamePair> = stmt.all();

    // Should find the pair of users with same email
    assert_eq!(results.len(), 2); // Both directions of the join

    // Verify both users are in the results
    let names: Vec<String> = results
        .iter()
        .flat_map(|pair| vec![pair.name1.clone(), pair.name2.clone()])
        .collect();
    assert!(names.contains(&"user1".to_string()));
    assert!(names.contains(&"user2".to_string()));
}

#[cfg(feature = "uuid")]
#[drizzle::test]
fn multiple_table_aliases_join(db: &mut TestDb<ComplexPostSchema>) {
    let ComplexPostSchema { complex, post } = schema;

    // Insert test users
    let user_id1 = uuid::Uuid::new_v4();
    let user_id2 = uuid::Uuid::new_v4();

    let users = vec![
        InsertComplex::new("author1", true, Role::User).with_id(user_id1),
        InsertComplex::new("author2", true, Role::User).with_id(user_id2),
    ];

    db.insert(complex).values(users).execute();

    // Insert test posts
    let posts = vec![
        InsertPost::new("First Post", true).with_author_id(user_id1),
        InsertPost::new("Second Post", true).with_author_id(user_id2),
        InsertPost::new("Third Post", false).with_author_id(user_id1),
    ];

    db.insert(post).values(posts).execute();

    // Join with aliases
    let u = Complex::alias::<AliasU>();
    let p = Post::alias::<AliasP>();

    let stmt = db
        .select((u.name.alias("user_name"), p.title.alias("post_title")))
        .from(u)
        .inner_join((p, eq(u.id, p.author_id)))
        .r#where(eq(p.published, true))
        .order_by([asc(u.name)]);
    let results: Vec<JoinResult> = stmt.all();

    assert_eq!(results.len(), 2);
    assert_eq!(results[0].user_name, "author1");
    assert_eq!(results[0].post_title, "First Post");
    assert_eq!(results[1].user_name, "author2");
    assert_eq!(results[1].post_title, "Second Post");
}

#[drizzle::test]
fn alias_with_original_table_comparison(db: &mut TestDb<SimpleSchema>) {
    let SimpleSchema { simple } = schema;

    // Insert test data
    let test_data = vec![InsertSimple::new("original"), InsertSimple::new("aliased")];

    db.insert(simple).values(test_data).execute();

    // Query using original table reference
    let original_results: Vec<SimpleResult> = db
        .select((simple.id, simple.name))
        .from(simple)
        .r#where(eq(simple.name, "original"))
        .all();

    // Query using table alias
    let s_alias = Simple::alias::<AliasSimple>();
    let alias_stmt = db
        .select((s_alias.id, s_alias.name))
        .from(s_alias)
        .r#where(eq(s_alias.name, "aliased"));
    let alias_results: Vec<SimpleResult> = alias_stmt.all();

    assert_eq!(original_results.len(), 1);
    assert_eq!(original_results[0].name, "original");

    assert_eq!(alias_results.len(), 1);
    assert_eq!(alias_results[0].name, "aliased");
}

#[drizzle::test]
fn tagged_alias_forwards_alias_metadata(db: &mut TestDb<SimpleSchema>) {
    let tagged = Simple::alias::<AliasSimple>();
    let _base = Simple::new();

    assert_eq!(tagged.name(), "s_alias");
}