#![cfg(any(feature = "rusqlite", feature = "turso", feature = "libsql"))]
#[cfg(feature = "uuid")]
use crate::common::schema::sqlite::Role;
use drizzle::core::expr::*;
use drizzle::sqlite::prelude::*;
#[cfg(feature = "uuid")]
use uuid::Uuid;
#[cfg(not(feature = "uuid"))]
use crate::common::schema::sqlite::Post;
#[cfg(feature = "uuid")]
use crate::common::schema::sqlite::{Complex, InsertComplex, InsertPost, Post, SelectPost};
#[SQLiteTable]
pub struct FkParent {
#[column(primary, autoincrement)]
pub id: i32,
pub name: String,
}
#[SQLiteTable]
pub struct FkSetDefault {
#[column(primary, autoincrement)]
pub id: i32,
#[column(references = FkParent::id, on_delete = SET_DEFAULT, default = 0)]
pub parent_id: i32,
pub value: String,
}
#[SQLiteTable]
pub struct FkCascade {
#[column(primary, autoincrement)]
pub id: i32,
#[column(references = FkParent::id, on_delete = CASCADE)]
pub parent_id: Option<i32>,
pub value: String,
}
#[SQLiteTable]
pub struct CompositeFkParent {
#[column(primary)]
pub id_a: i32,
#[column(primary)]
pub id_b: i32,
pub label: String,
}
#[SQLiteTable(FOREIGN_KEY(
columns(parent_a, parent_b),
references(CompositeFkParent, id_a, id_b),
on_delete = "CASCADE",
on_update = "CASCADE"
))]
pub struct CompositeFkChild {
#[column(primary, autoincrement)]
pub id: i32,
pub parent_a: Option<i32>,
pub parent_b: Option<i32>,
pub value: String,
}
#[derive(SQLiteSchema)]
pub struct FkCascadeSchema {
pub fk_parent: FkParent,
pub fk_cascade: FkCascade,
}
#[derive(SQLiteSchema)]
pub struct CompositeFkSchema {
pub composite_fk_parent: CompositeFkParent,
pub composite_fk_child: CompositeFkChild,
}
#[derive(SQLiteSchema)]
pub struct FkSetDefaultSchema {
pub fk_parent: FkParent,
pub fk_set_default: FkSetDefault,
}
#[allow(dead_code)]
#[derive(Debug, SQLiteFromRow)]
struct ParentResult {
id: i32,
name: String,
}
#[allow(dead_code)]
#[derive(Debug, SQLiteFromRow)]
struct ChildDefaultResult {
id: i32,
parent_id: i32,
value: String,
}
#[test]
fn test_on_delete_set_default_sql() {
let sql = FkSetDefault::create_table_sql();
assert!(
sql.contains("ON DELETE SET DEFAULT"),
"Should contain ON DELETE SET DEFAULT. Got: {}",
sql
);
}
#[test]
fn test_foreign_key_reference_sql() {
let post_sql = Post::create_table_sql();
assert!(post_sql.contains("CREATE TABLE"));
assert!(post_sql.contains("posts"));
assert!(
post_sql.contains("REFERENCES"),
"Post table should contain REFERENCES for foreign key"
);
assert!(
post_sql.contains("complex"),
"Post table should reference complex table"
);
assert!(
post_sql.contains("`id`"),
"Post table should reference id column. Got: {}",
post_sql
);
}
#[drizzle::test]
fn test_set_default_sets_default_value(db: &mut TestDb<FkSetDefaultSchema>) {
let FkSetDefaultSchema {
fk_parent,
fk_set_default,
} = schema;
db.insert(fk_parent)
.values([InsertFkParent::new("DefaultParent").with_id(0)])
.execute();
db.insert(fk_parent)
.values([InsertFkParent::new("Parent1")])
.execute();
let parents: Vec<ParentResult> = db
.select(())
.from(fk_parent)
.r#where(eq(fk_parent.name, "Parent1"))
.all();
let parent_id = parents[0].id;
db.insert(fk_set_default)
.values([InsertFkSetDefault::new("Child1").with_parent_id(parent_id)])
.execute();
let children: Vec<ChildDefaultResult> = db.select(()).from(fk_set_default).all();
assert_eq!(1, children.len());
assert_eq!(parent_id, children[0].parent_id);
db.delete(fk_parent)
.r#where(eq(fk_parent.id, parent_id))
.execute();
let children: Vec<ChildDefaultResult> = db.select(()).from(fk_set_default).all();
assert_eq!(1, children.len(), "Child should still exist");
assert_eq!(
0, children[0].parent_id,
"Parent ID should be default (0) after SET DEFAULT"
);
}
#[cfg(feature = "uuid")]
#[derive(SQLiteSchema)]
pub struct ComplexPostSchema {
pub complex: Complex,
pub post: Post,
}
#[cfg(feature = "uuid")]
#[drizzle::test]
fn test_foreign_key_impl(db: &mut TestDb<ComplexPostSchema>) {
let ComplexPostSchema { complex, post } = schema;
let id = Uuid::new_v4();
db.insert(complex)
.values([InsertComplex::new("John", false, Role::User).with_id(id)])
.execute();
db.insert(post)
.values([InsertPost::new("test", true).with_author_id(id)])
.execute();
let row: SelectPost = db
.select(())
.from(post)
.r#where(eq(post.author_id, id))
.get();
assert_eq!(Some(id), row.author_id);
}