#![cfg(any(feature = "rusqlite", feature = "turso", feature = "libsql"))]
#![allow(clippy::approx_constant)]
use drizzle::core::expr::*;
use drizzle::sqlite::prelude::*;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[SQLiteTable]
struct AllTypes {
#[column(PRIMARY)]
id: i32,
text_field: String,
int_field: i32,
real_field: f64,
blob_field: Vec<u8>,
bool_field: bool,
}
#[SQLiteTable(NAME = "pk_variations")]
struct PrimaryKeyVariations {
#[column(PRIMARY, AUTOINCREMENT)]
auto_id: i32,
name: String,
}
#[SQLiteTable(NAME = "manual_pk")]
struct ManualPrimaryKey {
#[column(PRIMARY)]
manual_id: String,
description: String,
}
#[SQLiteTable]
struct UniqueFields {
#[column(PRIMARY, AUTOINCREMENT)]
id: i32,
#[column(UNIQUE)]
email: String,
#[column(UNIQUE)]
username: String,
display_name: Option<String>,
}
#[SQLiteTable(NAME = "compile_defaults")]
struct CompileTimeDefaults {
#[column(PRIMARY, AUTOINCREMENT)]
id: i32,
#[column(DEFAULT = "default_name")]
name: String,
#[column(DEFAULT = 42)]
answer: i32,
#[column(DEFAULT = 3.14)]
pi: f64,
#[column(DEFAULT = true)]
active: bool,
#[column(DEFAULT = "pending")]
status: String,
}
#[SQLiteTable]
struct RuntimeDefaults {
#[column(PRIMARY, AUTOINCREMENT)]
id: i32,
#[column(DEFAULT_FN = String::new)]
empty_text: String,
#[column(DEFAULT_FN = || 100)]
computed_int: i32,
name: String,
}
#[derive(SQLiteEnum, Default, Clone, PartialEq, Debug, Copy)]
enum Priority {
Low = 1,
#[default]
Medium = 2,
High = 3,
}
#[derive(SQLiteEnum, Default, Clone, PartialEq, Debug, Copy)]
enum TaskStatus {
#[default]
Todo,
InProgress,
Done,
}
#[SQLiteTable]
struct EnumFields {
#[column(PRIMARY, AUTOINCREMENT)]
id: i32,
#[column(INTEGER, ENUM)]
priority: Priority,
#[column(ENUM)]
status: TaskStatus,
description: String,
}
#[SQLiteTable]
struct ComplexEnumFields {
#[column(PRIMARY, AUTOINCREMENT)]
id: i32,
notes: String,
}
#[cfg(feature = "serde")]
#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq)]
struct JsonData {
value: i32,
message: String,
}
#[cfg(feature = "serde")]
#[SQLiteTable]
struct JsonFields {
#[column(PRIMARY, AUTOINCREMENT)]
id: i32,
#[column(JSON)]
text_json: Option<JsonData>,
regular_text: String,
}
#[cfg(feature = "uuid")]
#[SQLiteTable]
struct UuidFields {
#[column(PRIMARY, DEFAULT_FN = uuid::Uuid::new_v4)]
id: uuid::Uuid,
name: String,
other_uuid: Option<uuid::Uuid>,
}
#[SQLiteTable]
struct NullableTest {
#[column(PRIMARY, AUTOINCREMENT)]
id: i32,
required_text: String,
required_int: i32,
required_bool: bool,
optional_text: Option<String>,
optional_int: Option<i32>,
optional_real: Option<f64>,
optional_blob: Option<Vec<u8>>,
optional_bool: Option<bool>,
}
#[derive(SQLiteSchema)]
struct AllTypesSchema {
all_types: AllTypes,
}
#[derive(SQLiteSchema)]
struct PrimaryKeyVariationsSchema {
pk_variations: PrimaryKeyVariations,
}
#[derive(SQLiteSchema)]
struct ManualPrimaryKeySchema {
manual_pk: ManualPrimaryKey,
}
#[derive(SQLiteSchema)]
struct UniqueFieldsSchema {
unique_fields: UniqueFields,
}
#[derive(SQLiteSchema)]
struct CompileTimeDefaultsSchema {
compile_defaults: CompileTimeDefaults,
}
#[derive(SQLiteSchema)]
struct RuntimeDefaultsSchema {
runtime_defaults: RuntimeDefaults,
}
#[derive(SQLiteSchema)]
struct EnumFieldsSchema {
enum_fields: EnumFields,
}
#[derive(SQLiteSchema)]
struct ComplexEnumFieldsSchema {
complex_enum_fields: ComplexEnumFields,
}
#[cfg(feature = "serde")]
#[derive(SQLiteSchema)]
struct JsonFieldsSchema {
json_fields: JsonFields,
}
#[cfg(feature = "uuid")]
#[derive(SQLiteSchema)]
struct UuidFieldsSchema {
uuid_fields: UuidFields,
}
#[derive(SQLiteSchema)]
struct NullableTestSchema {
nullable_test: NullableTest,
}
#[drizzle::test]
fn test_all_column_types(db: &mut TestDb<AllTypesSchema>) {
let all_types = schema.all_types;
let test_data = InsertAllTypes::new("test text", 123, 45.67, [1, 2, 3, 4, 5], true);
let result = db.insert(all_types).values([test_data]).execute();
assert_eq!(result, 1);
}
#[drizzle::test]
fn test_primary_key_autoincrement(db: &mut TestDb<PrimaryKeyVariationsSchema>) {
let pk_table = schema.pk_variations;
let data1 = InsertPrimaryKeyVariations::new("first");
let data2 = InsertPrimaryKeyVariations::new("second");
db.insert(pk_table).values([data1]).execute();
db.insert(pk_table).values([data2]).execute();
let select_query = db
.select((pk_table.auto_id, pk_table.name))
.from(pk_table)
.order_by(pk_table.auto_id);
#[derive(SQLiteFromRow, Debug, PartialEq)]
struct ReturnResult(i32, String);
let results: Vec<ReturnResult> = db.all(select_query);
assert_eq!(results.len(), 2);
assert_eq!(results[0], ReturnResult(1, "first".to_string()));
assert_eq!(results[1], ReturnResult(2, "second".to_string()));
}
#[drizzle::test]
fn test_manual_primary_key(db: &mut TestDb<ManualPrimaryKeySchema>) {
let manual_pk = schema.manual_pk;
let data = InsertManualPrimaryKey::new("custom_id_123", "Test description");
let result = db.insert(manual_pk).values([data]).execute();
assert_eq!(result, 1);
let select_query = db
.select(())
.from(manual_pk)
.r#where(eq(manual_pk.manual_id, "custom_id_123"));
#[derive(SQLiteFromRow, Debug, PartialEq)]
struct ReturnResult(String, String);
let results: Vec<ReturnResult> = db.all(select_query);
assert_eq!(results.len(), 1);
assert_eq!(results[0].0, "custom_id_123");
assert_eq!(results[0].1, "Test description");
}
#[drizzle::test]
fn test_unique_constraints(db: &mut TestDb<UniqueFieldsSchema>) {
let unique_table = schema.unique_fields;
let data1 =
InsertUniqueFields::new("test@example.com", "testuser").with_display_name("Test User");
let result1 = db.insert(unique_table).values([data1]).execute();
assert_eq!(result1, 1);
let data2 = InsertUniqueFields::new("test@example.com", "anotheruser")
.with_display_name("Another User");
let result2 = result!(db.insert(unique_table).values([data2]).execute());
assert!(result2.is_err()); }
#[drizzle::test]
fn test_compile_time_defaults(db: &mut TestDb<CompileTimeDefaultsSchema>) {
let defaults_table = schema.compile_defaults;
let data = InsertCompileTimeDefaults::new();
let result = db.insert(defaults_table).values([data]).execute();
assert_eq!(result, 1);
let select_query = db
.select((
defaults_table.name,
defaults_table.answer,
defaults_table.pi,
defaults_table.active,
defaults_table.status,
))
.from(defaults_table)
.r#where(eq(defaults_table.id, 1));
#[derive(SQLiteFromRow, Debug)]
struct ReturnResult(String, i32, f64, bool, String);
let results: Vec<ReturnResult> = db.all(select_query);
assert_eq!(results.len(), 1);
assert_eq!(results[0].0, "default_name");
assert_eq!(results[0].1, 42);
assert!((results[0].2 - 3.14).abs() < f64::EPSILON);
assert!(results[0].3);
assert_eq!(results[0].4, "pending");
}
#[drizzle::test]
fn test_runtime_defaults(db: &mut TestDb<RuntimeDefaultsSchema>) {
let RuntimeDefaultsSchema { runtime_defaults } = schema;
let data = InsertRuntimeDefaults::new("test");
let result = db.insert(runtime_defaults).values([data]).execute();
assert_eq!(result, 1);
let select_query = db
.select((
runtime_defaults.empty_text,
runtime_defaults.computed_int,
runtime_defaults.name,
))
.from(runtime_defaults)
.r#where(eq(runtime_defaults.id, 1));
#[derive(SQLiteFromRow, Debug)]
struct ReturnResult(String, i32, String);
let results: Vec<ReturnResult> = db.all(select_query);
assert_eq!(results.len(), 1);
assert_eq!(results[0].0, ""); assert_eq!(results[0].1, 100); assert_eq!(results[0].2, "test");
}
#[drizzle::test]
fn test_enum_storage_types(db: &mut TestDb<EnumFieldsSchema>) {
let enum_table = schema.enum_fields;
let data = InsertEnumFields::new(Priority::High, TaskStatus::InProgress, "Test task");
let result = db.insert(enum_table).values([data]).execute();
assert_eq!(result, 1);
let priority_col = enum_table.priority;
let status_col = enum_table.status;
let select_query = db
.select((
priority_col,
status_col,
alias(r#typeof(priority_col), "priority_type"),
alias(r#typeof(status_col), "status_type"),
))
.from(enum_table)
.r#where(eq(enum_table.id, 1));
#[derive(SQLiteFromRow, Debug)]
struct ReturnResult(i32, String, String, String);
let results: Vec<ReturnResult> = db.all(select_query);
assert_eq!(results.len(), 1);
assert_eq!(results[0].0, 3); assert_eq!(results[0].1, "InProgress"); assert_eq!(results[0].2, "integer"); assert_eq!(results[0].3, "text"); }
#[drizzle::test]
fn test_enum_full_round_trip(db: &mut TestDb<EnumFieldsSchema>) {
let enum_table = schema.enum_fields;
let data = vec![
InsertEnumFields::new(Priority::High, TaskStatus::Done, "urgent"),
InsertEnumFields::new(Priority::Medium, TaskStatus::InProgress, "normal"),
InsertEnumFields::new(Priority::Low, TaskStatus::Todo, "backlog"),
];
db.insert(enum_table).values(data).execute();
let results: Vec<SelectEnumFields> = db
.select(())
.from(enum_table)
.order_by(asc(enum_table.id))
.all();
assert_eq!(results.len(), 3);
assert_eq!(results[0].priority, Priority::High);
assert_eq!(results[1].priority, Priority::Medium);
assert_eq!(results[2].priority, Priority::Low);
assert_eq!(results[0].status, TaskStatus::Done);
assert_eq!(results[1].status, TaskStatus::InProgress);
assert_eq!(results[2].status, TaskStatus::Todo);
}
#[drizzle::test]
fn test_enum_where_conditions(db: &mut TestDb<EnumFieldsSchema>) {
let enum_table = schema.enum_fields;
let data = vec![
InsertEnumFields::new(Priority::High, TaskStatus::Done, "task 1"),
InsertEnumFields::new(Priority::High, TaskStatus::Todo, "task 2"),
InsertEnumFields::new(Priority::Low, TaskStatus::Done, "task 3"),
];
db.insert(enum_table).values(data).execute();
let results: Vec<SelectEnumFields> = db
.select(())
.from(enum_table)
.r#where(eq(enum_table.priority, Priority::High))
.all();
assert_eq!(results.len(), 2);
assert!(results.iter().all(|r| r.priority == Priority::High));
let results: Vec<SelectEnumFields> = db
.select(())
.from(enum_table)
.r#where(eq(enum_table.status, TaskStatus::Done))
.all();
assert_eq!(results.len(), 2);
assert!(results.iter().all(|r| r.status == TaskStatus::Done));
}
#[cfg(feature = "serde")]
#[drizzle::test]
fn test_json_storage_types(db: &mut TestDb<JsonFieldsSchema>) {
let json_table = schema.json_fields;
let json_data = JsonData {
value: 42,
message: "Hello JSON".to_string(),
};
let data = InsertJsonFields::new("regular").with_text_json(json_data);
let result = db.insert(json_table).values([data]).execute();
assert_eq!(result, 1);
let text_json_col = json_table.text_json;
let select_query = db
.select(alias(r#typeof(text_json_col), "text_type"))
.from(json_table)
.r#where(eq(json_table.id, 1));
#[derive(SQLiteFromRow, Debug)]
struct ReturnResult(String);
let results: Vec<ReturnResult> = db.all(select_query);
assert_eq!(results.len(), 1);
assert_eq!(results[0].0, "text"); }
#[cfg(feature = "uuid")]
#[drizzle::test]
fn test_uuid_primary_key_with_default_fn(db: &mut TestDb<UuidFieldsSchema>) {
let uuid_table = schema.uuid_fields;
let data = InsertUuidFields::new("uuid test");
let result = db.insert(uuid_table).values([data]).execute();
assert_eq!(result, 1);
let select_query = db
.select((uuid_table.id, uuid_table.name))
.from(uuid_table)
.r#where(eq(uuid_table.name, "uuid test"));
#[derive(SQLiteFromRow, Debug)]
struct ReturnResult(uuid::Uuid, String);
let results: Vec<ReturnResult> = db.all(select_query);
assert_eq!(results.len(), 1);
assert_eq!(results[0].1, "uuid test");
let generated_uuid = results[0].0;
assert_ne!(generated_uuid, uuid::Uuid::nil());
assert_eq!(generated_uuid.get_version(), Some(uuid::Version::Random));
let id_col = uuid_table.id;
let type_query = db
.select(alias(r#typeof(id_col), "id_type"))
.from(uuid_table)
.r#where(eq(uuid_table.name, "uuid test"));
#[derive(SQLiteFromRow, Debug)]
struct TypeResult(String);
let type_results: Vec<TypeResult> = db.all(type_query);
assert_eq!(type_results.len(), 1);
assert_eq!(type_results[0].0, "blob"); }
#[drizzle::test]
fn test_nullable_vs_non_nullable(db: &mut TestDb<NullableTestSchema>) {
let nullable_table = schema.nullable_test;
let minimal_data = InsertNullableTest::new("required", 123, true);
let result = db.insert(nullable_table).values([minimal_data]).execute();
assert_eq!(result, 1);
let full_data = InsertNullableTest::new("full", 456, false)
.with_optional_text("optional text")
.with_optional_int(789)
.with_optional_real(12.34)
.with_optional_blob([9, 8, 7])
.with_optional_bool(true);
let result = db.insert(nullable_table).values([full_data]).execute();
assert_eq!(result, 1);
let select_query = db
.select((
nullable_table.required_text,
nullable_table.optional_text,
nullable_table.optional_int,
))
.from(nullable_table)
.order_by(nullable_table.id);
#[derive(SQLiteFromRow, Debug)]
struct ReturnResult(String, Option<String>, Option<i32>);
let results: Vec<ReturnResult> = db.all(select_query);
assert_eq!(results.len(), 2);
assert_eq!(results[0].0, "required");
assert_eq!(results[0].1, None);
assert_eq!(results[0].2, None);
assert_eq!(results[1].0, "full");
assert_eq!(results[1].1, Some("optional text".to_string()));
assert_eq!(results[1].2, Some(789));
}
#[test]
fn test_schema_generation() {
let _ = AllTypes::SQL;
let _ = PrimaryKeyVariations::SQL;
let _ = UniqueFields::SQL;
let _ = CompileTimeDefaults::SQL;
let _ = RuntimeDefaults::SQL;
let _ = EnumFields::SQL;
let _ = NullableTest::SQL;
#[cfg(feature = "serde")]
let _ = JsonFields::SQL;
#[cfg(feature = "uuid")]
let _ = UuidFields::SQL;
}