#![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::{ComplexSchema, InsertComplex};
use crate::common::schema::sqlite::{InsertSimple, SelectSimple, Simple, SimpleSchema};
use drizzle::core::expr::*;
use drizzle::sqlite::prelude::*;
#[derive(Debug, SQLiteFromRow)]
struct CountResult {
count: i64,
}
#[derive(Debug, SQLiteFromRow)]
struct SumResult {
sum: Option<i32>,
}
#[derive(Debug, SQLiteFromRow)]
struct MinResult {
min: Option<i32>,
}
#[derive(Debug, SQLiteFromRow)]
struct MaxResult {
max: Option<i32>,
}
#[derive(Debug, SQLiteFromRow)]
struct AvgResult {
avg: Option<f64>,
}
#[cfg(feature = "uuid")]
#[derive(Debug, SQLiteFromRow)]
struct SumRealResult {
sum: Option<f64>,
}
#[cfg(feature = "uuid")]
#[derive(Debug, SQLiteFromRow)]
struct MinRealResult {
min: Option<f64>,
}
#[cfg(feature = "uuid")]
#[derive(Debug, SQLiteFromRow)]
struct MaxRealResult {
max: Option<f64>,
}
#[derive(Debug, SQLiteFromRow)]
struct DistinctResult {
name: String,
}
#[derive(Debug, SQLiteFromRow)]
struct CoalesceStringResult {
coalesce: String,
}
#[derive(Debug, SQLiteFromRow)]
struct CoalesceManyStringResult {
value: String,
}
#[cfg(feature = "uuid")]
#[derive(Debug, SQLiteFromRow)]
struct CoalesceIntResult {
coalesce: i32,
}
#[derive(Debug, SQLiteFromRow)]
struct AliasResult {
item_name: String,
}
#[derive(Debug, SQLiteFromRow)]
struct CountAliasResult {
total_count: i64,
}
#[derive(Debug, SQLiteFromRow)]
struct SumAliasResult {
id_sum: Option<i32>,
}
#[cfg(feature = "uuid")]
#[derive(Debug, SQLiteFromRow)]
struct ComplexAggregateResult {
count: i64,
avg: Option<f64>,
max_age: i32,
}
#[cfg(feature = "uuid")]
#[derive(Debug, SQLiteFromRow)]
struct CoalesceAvgResult {
coalesce: f64,
}
#[drizzle::test]
fn test_cast_sql_generation(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let stmt = db
.select(alias(
cast(simple.id, drizzle::sqlite::types::Integer),
"id_int",
))
.from(simple);
assert_eq!(
stmt.to_sql().sql(),
r#"SELECT CAST ("simple"."id" AS INTEGER) AS "id_int" FROM "simple""#
);
}
#[drizzle::test]
fn test_aggregate_functions(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("Item A").with_id(10),
InsertSimple::new("Item B").with_id(20),
InsertSimple::new("Item C").with_id(30),
InsertSimple::new("Item D").with_id(40),
];
db.insert(simple).values(test_data).execute();
let stmt = db.select(alias(count(()), "count")).from(simple);
assert_eq!(
stmt.to_sql().sql(),
r#"SELECT COUNT(*) AS "count" FROM "simple""#
);
let result: Vec<CountResult> = stmt.all();
assert_eq!(result[0].count, 4);
let result: Vec<CountResult> = db
.select(alias(count(simple.id), "count"))
.from(simple)
.all();
assert_eq!(result[0].count, 4);
let result: Vec<SumResult> = db.select(alias(sum(simple.id), "sum")).from(simple).all();
assert_eq!(result[0].sum, Some(100));
let result: Vec<MinResult> = db.select(alias(min(simple.id), "min")).from(simple).all();
assert_eq!(result[0].min, Some(10));
let result: Vec<MaxResult> = db.select(alias(max(simple.id), "max")).from(simple).all();
assert_eq!(result[0].max, Some(40));
let result: Vec<AvgResult> = db.select(alias(avg(simple.id), "avg")).from(simple).all();
assert_eq!(result[0].avg, Some(25.0));
}
#[drizzle::test]
fn test_ne_condition(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
db.insert(simple)
.values([
InsertSimple::new("alice").with_id(1),
InsertSimple::new("bob").with_id(2),
])
.execute();
let stmt = db
.select((simple.id, simple.name))
.from(simple)
.r#where(ne(simple.id, 1));
assert_eq!(
stmt.to_sql().sql(),
r#"SELECT "simple"."id", "simple"."name" FROM "simple" WHERE "simple"."id" <> ?"#
);
let rows: Vec<SelectSimple> = stmt.all();
assert_eq!(rows.len(), 1);
assert_eq!(rows[0].id, 2);
assert_eq!(rows[0].name, "bob");
}
#[cfg(feature = "uuid")]
#[drizzle::test]
fn test_aggregate_functions_with_real_numbers(db: &mut TestDb<ComplexSchema>) {
let ComplexSchema { complex } = schema;
let test_data = vec![
InsertComplex::new("User A", true, Role::User).with_score(85.5),
InsertComplex::new("User B", false, Role::Admin).with_score(92.0),
InsertComplex::new("User C", true, Role::User).with_score(78.3),
InsertComplex::new("User D", false, Role::User).with_score(88.7),
];
db.insert(complex).values(test_data).execute();
let result: Vec<CountResult> = db
.select(alias(count(complex.score), "count"))
.from(complex)
.all();
assert_eq!(result[0].count, 4);
let result: Vec<SumRealResult> = db
.select(alias(sum(complex.score), "sum"))
.from(complex)
.all();
assert!((result[0].sum.expect("sum") - 344.5).abs() < 0.1);
let result: Vec<AvgResult> = db
.select(alias(avg(complex.score), "avg"))
.from(complex)
.all();
assert!((result[0].avg.expect("avg") - 86.125).abs() < 0.1);
let result: Vec<MinRealResult> = db
.select(alias(min(complex.score), "min"))
.from(complex)
.all();
assert!((result[0].min.expect("min") - 78.3).abs() < 0.1);
let result: Vec<MaxRealResult> = db
.select(alias(max(complex.score), "max"))
.from(complex)
.all();
assert!((result[0].max.expect("max") - 92.0).abs() < 0.1);
}
#[drizzle::test]
fn test_distinct_expression(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("Apple").with_id(1),
InsertSimple::new("Apple").with_id(2),
InsertSimple::new("Banana").with_id(3),
InsertSimple::new("Apple").with_id(4),
InsertSimple::new("Cherry").with_id(5),
];
db.insert(simple).values(test_data).execute();
let result: Vec<DistinctResult> = db
.select(alias(distinct(simple.name), "name"))
.from(simple)
.all();
assert_eq!(result.len(), 3);
let names: Vec<String> = result.iter().map(|r| r.name.clone()).collect();
assert!(names.contains(&"Apple".to_string()));
assert!(names.contains(&"Banana".to_string()));
assert!(names.contains(&"Cherry".to_string()));
let result: Vec<CountResult> = db
.select(alias(count(distinct(simple.name)), "count"))
.from(simple)
.all();
assert_eq!(result[0].count, 3);
}
#[cfg(feature = "uuid")]
#[drizzle::test]
fn test_coalesce_expression(db: &mut TestDb<ComplexSchema>) {
let ComplexSchema { complex } = schema;
db.insert(complex)
.values([
InsertComplex::new("User A", true, Role::User)
.with_email("user@example.com".to_string()),
InsertComplex::new("User C", true, Role::User)
.with_email("user3@example.com".to_string()),
])
.execute();
db.insert(complex)
.values([InsertComplex::new("User B", false, Role::Admin)])
.execute();
let result: Vec<CoalesceStringResult> = db
.select(alias(
coalesce(complex.email, "no-email@example.com"),
"coalesce",
))
.from(complex)
.all();
assert_eq!(result.len(), 3);
let emails: Vec<String> = result.iter().map(|r| r.coalesce.clone()).collect();
assert!(emails.contains(&"user@example.com".to_string()));
assert!(emails.contains(&"user3@example.com".to_string()));
assert!(emails.contains(&"no-email@example.com".to_string()));
let result: Vec<CoalesceIntResult> = db
.select(alias(coalesce(complex.age, 0), "coalesce"))
.from(complex)
.all();
assert_eq!(result.len(), 3);
assert!(result.iter().all(|r| r.coalesce == 0));
}
#[cfg(feature = "uuid")]
#[drizzle::test]
fn test_coalesce_many_expression(db: &mut TestDb<ComplexSchema>) {
let ComplexSchema { complex } = schema;
db.insert(complex)
.values([InsertComplex::new("User A", true, Role::User)
.with_email("user@example.com".to_string())])
.execute();
db.insert(complex)
.values([InsertComplex::new("User B", false, Role::Admin)])
.execute();
let result: Vec<CoalesceManyStringResult> = db
.select(alias(
coalesce_many(complex.email, ["no-email@example.com"]),
"value",
))
.from(complex)
.all();
assert_eq!(result.len(), 2);
let values: Vec<String> = result.iter().map(|r| r.value.clone()).collect();
assert!(values.contains(&"user@example.com".to_string()));
assert!(values.contains(&"no-email@example.com".to_string()));
}
#[drizzle::test]
fn test_alias_expression(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![InsertSimple::new("Test Item").with_id(1)];
db.insert(simple).values(test_data).execute();
let result: Vec<AliasResult> = db
.select(alias(simple.name, "item_name"))
.from(simple)
.all();
assert_eq!(result[0].item_name, "Test Item");
let result: Vec<CountAliasResult> = db
.select(alias(count(simple.id), "total_count"))
.from(simple)
.all();
assert_eq!(result[0].total_count, 1);
let result: Vec<SumAliasResult> = db
.select(alias(sum(simple.id), "id_sum"))
.from(simple)
.all();
assert_eq!(result[0].id_sum, Some(1));
}
#[cfg(feature = "uuid")]
#[drizzle::test]
fn test_complex_expressions(db: &mut TestDb<ComplexSchema>) {
let ComplexSchema { complex } = schema;
db.insert(complex)
.values([
InsertComplex::new("User A", true, Role::User)
.with_age(25)
.with_score(85.5),
InsertComplex::new("User B", false, Role::Admin)
.with_age(30)
.with_score(92.0),
])
.execute();
db.insert(complex)
.values([InsertComplex::new("User C", true, Role::User).with_score(78.3)])
.execute();
let result: Vec<ComplexAggregateResult> = db
.select((
alias(count(complex.id), "count"),
alias(avg(complex.score), "avg"),
alias(coalesce(max(complex.age), 0), "max_age"),
))
.from(complex)
.all();
assert_eq!(result[0].count, 3); assert!((result[0].avg.expect("avg") - 85.266).abs() < 0.1); assert_eq!(result[0].max_age, 30);
let result: Vec<CoalesceAvgResult> = db
.select(alias(coalesce(avg(complex.score), 0.0), "coalesce"))
.from(complex)
.r#where(is_not_null(complex.score))
.all();
assert!((result[0].coalesce - 85.266).abs() < 0.1);
}
#[cfg(feature = "uuid")]
#[drizzle::test]
fn test_expressions_with_conditions(db: &mut TestDb<ComplexSchema>) {
let ComplexSchema { complex } = schema;
let test_data = [
InsertComplex::new("Active User", true, Role::User).with_score(85.5),
InsertComplex::new("Active Admin", true, Role::Admin).with_score(92.0),
InsertComplex::new("Inactive User", false, Role::User).with_score(78.3),
InsertComplex::new("Inactive Admin", false, Role::Admin).with_score(88.7),
];
db.insert(complex).values(test_data).execute();
let result: Vec<CountResult> = db
.select(alias(count(complex.id), "count"))
.from(complex)
.r#where(eq(complex.active, true))
.all();
assert_eq!(result[0].count, 2);
let result: Vec<AvgResult> = db
.select(alias(avg(complex.score), "avg"))
.from(complex)
.r#where(eq(complex.role, Role::Admin))
.all();
assert!((result[0].avg.expect("avg") - 90.35).abs() < 0.1);
let result: Vec<MaxRealResult> = db
.select(alias(max(complex.score), "max"))
.from(complex)
.r#where(eq(complex.active, false))
.all();
assert!((result[0].max.expect("max") - 88.7).abs() < 0.1);
}
#[drizzle::test]
fn test_aggregate_with_empty_result(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let result: Vec<CountResult> = db
.select(alias(count(simple.id), "count"))
.from(simple)
.all();
assert_eq!(result[0].count, 0);
}
#[drizzle::test]
fn test_expression_edge_cases(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = [
InsertSimple::new("").with_id(0), InsertSimple::new("Test").with_id(1),
];
db.insert(simple).values(test_data).execute();
let result: Vec<CountResult> = db
.select(alias(count(simple.id), "count"))
.from(simple)
.all();
assert_eq!(result[0].count, 2);
let result: Vec<DistinctResult> = db
.select(alias(distinct(simple.name), "name"))
.from(simple)
.all();
assert_eq!(result.len(), 2);
let names: Vec<String> = result.iter().map(|r| r.name.clone()).collect();
assert!(names.contains(&"".to_string()));
assert!(names.contains(&"Test".to_string()));
let result: Vec<SumResult> = db.select(alias(sum(simple.id), "sum")).from(simple).all();
assert_eq!(result[0].sum, Some(1));
let result: Vec<CoalesceStringResult> = db
.select(alias(coalesce(simple.name, "default"), "coalesce"))
.from(simple)
.r#where(eq(simple.name, ""))
.all();
assert_eq!(result[0].coalesce, ""); }
#[drizzle::test]
fn test_multiple_aliases(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = [
InsertSimple::new("Item A").with_id(1),
InsertSimple::new("Item B").with_id(2),
];
db.insert(simple).values(test_data).execute();
#[derive(SQLiteFromRow)]
struct ResultRow {
identifier: i32,
item_name: String,
total: i64,
}
let result: Vec<ResultRow> = db
.select((
alias(simple.id, "identifier"),
alias(simple.name, "item_name"),
alias(count(simple.id), "total"),
))
.from(simple)
.group_by((simple.id, simple.name))
.all();
assert_eq!(result[0].identifier, 1);
assert_eq!(result[0].item_name, "Item A");
assert_eq!(result[0].total, 1);
}
#[drizzle::test]
fn test_cte_integration_simple(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
struct FilteredUsersTag;
impl drizzle::core::Tag for FilteredUsersTag {
const NAME: &'static str = "filtered_users";
}
#[derive(SQLiteFromRow)]
struct CteSimpleRow {
id: i32,
name: String,
}
let test_data = [
InsertSimple::new("Alice").with_id(1),
InsertSimple::new("Bob").with_id(2),
InsertSimple::new("Charlie").with_id(3),
];
db.insert(simple).values(test_data).execute();
let filtered_users = db
.select((simple.id, simple.name))
.from(simple)
.r#where(gt(simple.id, 1))
.into_cte::<FilteredUsersTag>();
let result: Vec<CteSimpleRow> = db
.with(&filtered_users)
.select(CteSimpleRow::Select)
.from(&filtered_users)
.all();
assert_eq!(result.len(), 2);
assert_eq!(result[0].id, 2);
assert_eq!(result[0].name, "Bob");
assert_eq!(result[1].id, 3);
assert_eq!(result[1].name, "Charlie");
}
#[drizzle::test]
fn test_cte_integration_with_aggregation(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
struct UserCountTag;
impl drizzle::core::Tag for UserCountTag {
const NAME: &'static str = "user_count";
}
let test_data = [
InsertSimple::new("Test1").with_id(1),
InsertSimple::new("Test2").with_id(2),
InsertSimple::new("Test3").with_id(3),
];
db.insert(simple).values(test_data).execute();
let user_count = db
.select(count(simple.id).alias("count"))
.from(simple)
.into_cte::<UserCountTag>();
#[derive(SQLiteFromRow)]
struct CountResult {
count: i64,
}
let result: Vec<CountResult> = db
.with(&user_count)
.select(CountResult::Select)
.from(&user_count)
.all();
assert_eq!(result.len(), 1);
assert_eq!(result[0].count, 3);
}
#[drizzle::test]
fn test_cte_complex_two_levels(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
struct FilteredUsersTag;
impl drizzle::core::Tag for FilteredUsersTag {
const NAME: &'static str = "filtered_users";
}
let test_data = [
InsertSimple::new("Alice").with_id(1),
InsertSimple::new("Bob").with_id(2),
InsertSimple::new("Charlie").with_id(3),
InsertSimple::new("David").with_id(4),
InsertSimple::new("Eve").with_id(5),
];
db.insert(simple).values(test_data).execute();
let filtered_users = db
.select((simple.id, simple.name))
.from(simple)
.r#where(gt(simple.id, 2))
.into_cte::<FilteredUsersTag>();
#[derive(SQLiteFromRow)]
struct StatsResult {
count: i64,
category: Option<String>,
}
let result: Vec<StatsResult> = db
.with(&filtered_users)
.select((
count(filtered_users.id).alias("count"),
min(filtered_users.name).alias("category"),
))
.from(&filtered_users)
.all();
assert_eq!(result.len(), 1);
assert_eq!(result[0].count, 3); assert_eq!(result[0].category, Some("Charlie".to_string()));
}
#[drizzle::test]
fn test_cte_after_join(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
struct SimpleTag;
impl drizzle::core::Tag for SimpleTag {
const NAME: &'static str = "simple_alias";
}
struct JoinedSimpleTag;
impl drizzle::core::Tag for JoinedSimpleTag {
const NAME: &'static str = "joined_simple";
}
let test_data = [
InsertSimple::new("Alpha").with_id(1),
InsertSimple::new("Beta").with_id(2),
InsertSimple::new("Gamma").with_id(3),
];
db.insert(simple).values(test_data).execute();
let simple_alias = Simple::alias::<SimpleTag>();
let joined_simple = db
.select((simple.id, simple.name))
.from(simple)
.join((simple_alias, eq(simple.id, simple_alias.id)))
.into_cte::<JoinedSimpleTag>();
let results: Vec<SelectSimple> = db
.with(&joined_simple)
.select((joined_simple.id, joined_simple.name))
.from(&joined_simple)
.order_by([asc(joined_simple.id)])
.all();
assert_eq!(results.len(), 3);
assert_eq!(results[0].name, "Alpha");
assert_eq!(results[2].name, "Gamma");
}
#[drizzle::test]
fn test_cte_after_order_limit_offset(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
struct PagedSimpleTag;
impl drizzle::core::Tag for PagedSimpleTag {
const NAME: &'static str = "paged_simple";
}
let test_data = [
InsertSimple::new("One").with_id(1),
InsertSimple::new("Two").with_id(2),
InsertSimple::new("Three").with_id(3),
InsertSimple::new("Four").with_id(4),
];
db.insert(simple).values(test_data).execute();
let paged_simple = db
.select((simple.id, simple.name))
.from(simple)
.order_by([asc(simple.id)])
.limit(2)
.offset(1)
.into_cte::<PagedSimpleTag>();
let results: Vec<SelectSimple> = db
.with(&paged_simple)
.select((paged_simple.id, paged_simple.name))
.from(&paged_simple)
.order_by([asc(paged_simple.id)])
.all();
assert_eq!(results.len(), 2);
assert_eq!(results[0].id, 2);
assert_eq!(results[1].id, 3);
}
#[drizzle::test]
fn test_modulo_operator(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("Item A").with_id(10),
InsertSimple::new("Item B").with_id(15),
InsertSimple::new("Item C").with_id(23),
];
db.insert(simple).values(test_data).execute();
let result: Vec<SelectSimple> = db
.select((simple.id, simple.name))
.from(simple)
.r#where(eq(simple.id % 5, 0))
.all();
assert_eq!(result.len(), 2);
assert_eq!(result[0].id, 10);
assert_eq!(result[1].id, 15);
let result: Vec<SelectSimple> = db
.select((simple.id, simple.name))
.from(simple)
.r#where(eq(simple.id % 10, 3))
.all();
assert_eq!(result.len(), 1);
assert_eq!(result[0].id, 23);
}
#[drizzle::test]
fn test_between_method(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("Item A").with_id(5),
InsertSimple::new("Item B").with_id(10),
InsertSimple::new("Item C").with_id(15),
InsertSimple::new("Item D").with_id(20),
InsertSimple::new("Item E").with_id(25),
];
db.insert(simple).values(test_data).execute();
let result: Vec<SelectSimple> = db
.select((simple.id, simple.name))
.from(simple)
.r#where(simple.id.between(10, 20))
.all();
assert_eq!(result.len(), 3);
assert_eq!(result[0].id, 10);
assert_eq!(result[1].id, 15);
assert_eq!(result[2].id, 20);
let result: Vec<SelectSimple> = db
.select((simple.id, simple.name))
.from(simple)
.r#where(simple.id.not_between(10, 20))
.all();
assert_eq!(result.len(), 2);
assert_eq!(result[0].id, 5);
assert_eq!(result[1].id, 25);
}
#[drizzle::test]
fn test_in_array_method(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("Alice").with_id(1),
InsertSimple::new("Bob").with_id(2),
InsertSimple::new("Charlie").with_id(3),
InsertSimple::new("David").with_id(4),
InsertSimple::new("Eve").with_id(5),
];
db.insert(simple).values(test_data).execute();
let result: Vec<SelectSimple> = db
.select((simple.id, simple.name))
.from(simple)
.r#where(simple.id.in_array([1, 3, 5]))
.all();
assert_eq!(result.len(), 3);
assert_eq!(result[0].name, "Alice");
assert_eq!(result[1].name, "Charlie");
assert_eq!(result[2].name, "Eve");
let result: Vec<SelectSimple> = db
.select((simple.id, simple.name))
.from(simple)
.r#where(simple.id.not_in_array([1, 3, 5]))
.all();
assert_eq!(result.len(), 2);
assert_eq!(result[0].name, "Bob");
assert_eq!(result[1].name, "David");
let result: Vec<SelectSimple> = db
.select((simple.id, simple.name))
.from(simple)
.r#where(simple.name.in_array(["Alice", "Eve"]))
.all();
assert_eq!(result.len(), 2);
assert_eq!(result[0].name, "Alice");
assert_eq!(result[1].name, "Eve");
}
#[drizzle::test]
fn test_column_arithmetic(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("Item A").with_id(10),
InsertSimple::new("Item B").with_id(20),
InsertSimple::new("Item C").with_id(30),
];
db.insert(simple).values(test_data).execute();
#[derive(Debug, SQLiteFromRow)]
struct ComputedResult {
computed: i32,
}
let result: Vec<ComputedResult> = db
.select(alias(simple.id * 2, "computed"))
.from(simple)
.all();
assert_eq!(result.len(), 3);
assert_eq!(result[0].computed, 20); assert_eq!(result[1].computed, 40); assert_eq!(result[2].computed, 60);
let result: Vec<SelectSimple> = db
.select((simple.id, simple.name))
.from(simple)
.r#where(lt(simple.id, 25))
.all();
assert_eq!(result.len(), 2);
assert_eq!(result[0].id, 10);
assert_eq!(result[1].id, 20);
}
#[derive(Debug, SQLiteFromRow)]
struct StringResult {
result: String,
}
#[derive(Debug, SQLiteFromRow)]
struct LengthResult {
length: i64,
}
#[derive(Debug, SQLiteFromRow)]
struct InstrResult {
position: i64,
}
#[drizzle::test]
fn test_string_upper_lower(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("Hello World").with_id(1),
InsertSimple::new("Test String").with_id(2),
];
db.insert(simple).values(test_data).execute();
let result: Vec<StringResult> = db
.select(alias(upper(simple.name), "result"))
.from(simple)
.r#where(eq(simple.id, 1))
.all();
assert_eq!(result[0].result, "HELLO WORLD");
let result: Vec<StringResult> = db
.select(alias(lower(simple.name), "result"))
.from(simple)
.r#where(eq(simple.id, 1))
.all();
assert_eq!(result[0].result, "hello world");
}
#[drizzle::test]
fn test_string_trim(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new(" trimmed ").with_id(1),
InsertSimple::new(" left").with_id(2),
InsertSimple::new("right ").with_id(3),
];
db.insert(simple).values(test_data).execute();
let result: Vec<StringResult> = db
.select(alias(trim(simple.name), "result"))
.from(simple)
.r#where(eq(simple.id, 1))
.all();
assert_eq!(result[0].result, "trimmed");
let result: Vec<StringResult> = db
.select(alias(ltrim(simple.name), "result"))
.from(simple)
.r#where(eq(simple.id, 2))
.all();
assert_eq!(result[0].result, "left");
let result: Vec<StringResult> = db
.select(alias(rtrim(simple.name), "result"))
.from(simple)
.r#where(eq(simple.id, 3))
.all();
assert_eq!(result[0].result, "right");
}
#[drizzle::test]
fn test_string_length(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("hello").with_id(1),
InsertSimple::new("").with_id(2),
InsertSimple::new("test string").with_id(3),
];
db.insert(simple).values(test_data).execute();
let result: Vec<LengthResult> = db
.select(alias(length(simple.name), "length"))
.from(simple)
.r#where(eq(simple.id, 1))
.all();
assert_eq!(result[0].length, 5);
let result: Vec<LengthResult> = db
.select(alias(length(simple.name), "length"))
.from(simple)
.r#where(eq(simple.id, 2))
.all();
assert_eq!(result[0].length, 0);
}
#[drizzle::test]
fn test_string_substr(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![InsertSimple::new("Hello World").with_id(1)];
db.insert(simple).values(test_data).execute();
let result: Vec<StringResult> = db
.select(alias(substr(simple.name, 1, 5), "result"))
.from(simple)
.all();
assert_eq!(result[0].result, "Hello");
let result: Vec<StringResult> = db
.select(alias(substr(simple.name, 7, 5), "result"))
.from(simple)
.all();
assert_eq!(result[0].result, "World");
}
#[drizzle::test]
fn test_string_replace(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![InsertSimple::new("Hello World").with_id(1)];
db.insert(simple).values(test_data).execute();
let result: Vec<StringResult> = db
.select(alias(replace(simple.name, "World", "Rust"), "result"))
.from(simple)
.all();
assert_eq!(result[0].result, "Hello Rust");
let result: Vec<StringResult> = db
.select(alias(replace(simple.name, "xyz", "abc"), "result"))
.from(simple)
.all();
assert_eq!(result[0].result, "Hello World");
}
#[drizzle::test]
fn test_string_instr(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![InsertSimple::new("Hello World").with_id(1)];
db.insert(simple).values(test_data).execute();
let result: Vec<InstrResult> = db
.select(alias(instr(simple.name, "World"), "position"))
.from(simple)
.all();
assert_eq!(result[0].position, 7);
let result: Vec<InstrResult> = db
.select(alias(instr(simple.name, "xyz"), "position"))
.from(simple)
.all();
assert_eq!(result[0].position, 0);
}
#[drizzle::test]
fn test_string_concat(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("Hello").with_id(1),
InsertSimple::new("World").with_id(2),
];
db.insert(simple).values(test_data).execute();
let result: Vec<StringResult> = db
.select(alias(concat(simple.name, "!"), "result"))
.from(simple)
.r#where(eq(simple.id, 1))
.all();
assert_eq!(result[0].result, "Hello!");
let result: Vec<StringResult> = db
.select(alias(concat(concat(simple.name, " "), "there"), "result"))
.from(simple)
.r#where(eq(simple.id, 1))
.all();
assert_eq!(result[0].result, "Hello there");
}
#[drizzle::test]
fn test_string_functions_combined(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![InsertSimple::new(" Hello World ").with_id(1)];
db.insert(simple).values(test_data).execute();
let result: Vec<StringResult> = db
.select(alias(upper(trim(simple.name)), "result"))
.from(simple)
.all();
assert_eq!(result[0].result, "HELLO WORLD");
let result: Vec<StringResult> = db
.select(alias(lower(trim(simple.name)), "result"))
.from(simple)
.all();
assert_eq!(result[0].result, "hello world");
let result: Vec<LengthResult> = db
.select(alias(length(trim(simple.name)), "length"))
.from(simple)
.all();
assert_eq!(result[0].length, 11); }
#[derive(Debug, SQLiteFromRow)]
struct MathIntResult {
result: i32,
}
#[derive(Debug, SQLiteFromRow)]
struct MathFloatResult {
result: f64,
}
#[drizzle::test]
fn test_math_abs(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("Negative").with_id(-10),
InsertSimple::new("Zero").with_id(0),
InsertSimple::new("Positive").with_id(10),
];
db.insert(simple).values(test_data).execute();
let result: Vec<MathIntResult> = db
.select(alias(abs(simple.id), "result"))
.from(simple)
.r#where(eq(simple.name, "Negative"))
.all();
assert_eq!(result[0].result, 10);
let result: Vec<MathIntResult> = db
.select(alias(abs(simple.id), "result"))
.from(simple)
.r#where(eq(simple.name, "Zero"))
.all();
assert_eq!(result[0].result, 0);
}
#[drizzle::test]
fn test_math_round(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![InsertSimple::new("Test").with_id(37)];
db.insert(simple).values(test_data).execute();
let result: Vec<MathFloatResult> = db
.select(alias(round(simple.id / 10), "result"))
.from(simple)
.all();
assert_eq!(result[0].result, 3.0);
}
#[drizzle::test]
fn test_math_sign(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("Negative").with_id(-5),
InsertSimple::new("Zero").with_id(0),
InsertSimple::new("Positive").with_id(5),
];
db.insert(simple).values(test_data).execute();
let result: Vec<MathFloatResult> = db
.select(alias(sign(simple.id), "result"))
.from(simple)
.r#where(eq(simple.name, "Negative"))
.all();
assert_eq!(result[0].result, -1.0);
let result: Vec<MathFloatResult> = db
.select(alias(sign(simple.id), "result"))
.from(simple)
.r#where(eq(simple.name, "Zero"))
.all();
assert_eq!(result[0].result, 0.0);
let result: Vec<MathFloatResult> = db
.select(alias(sign(simple.id), "result"))
.from(simple)
.r#where(eq(simple.name, "Positive"))
.all();
assert_eq!(result[0].result, 1.0);
}
#[drizzle::test]
fn test_math_mod(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("Ten").with_id(10),
InsertSimple::new("Seven").with_id(7),
InsertSimple::new("Fifteen").with_id(15),
];
db.insert(simple).values(test_data).execute();
let result: Vec<MathIntResult> = db
.select(alias(mod_(simple.id, 3), "result"))
.from(simple)
.r#where(eq(simple.name, "Ten"))
.all();
assert_eq!(result[0].result, 1);
let result: Vec<MathIntResult> = db
.select(alias(mod_(simple.id, 4), "result"))
.from(simple)
.r#where(eq(simple.name, "Fifteen"))
.all();
assert_eq!(result[0].result, 3);
}
#[derive(Debug, SQLiteFromRow)]
struct DateResult {
result: String,
}
#[derive(Debug, SQLiteFromRow)]
struct CurrentDateResult {
today: String,
}
#[drizzle::test]
fn test_datetime_current(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![InsertSimple::new("Test").with_id(1)];
db.insert(simple).values(test_data).execute();
let result: Vec<CurrentDateResult> = db
.select(alias(
cast(current_date(), drizzle::sqlite::types::Text),
"today",
))
.from(simple)
.all();
assert!(result[0].today.len() == 10);
assert!(result[0].today.contains('-'));
}
#[drizzle::test]
fn test_datetime_strftime(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![InsertSimple::new("Test").with_id(1)];
db.insert(simple).values(test_data).execute();
let result: Vec<DateResult> = db
.select(alias(strftime("%Y", current_date()), "result"))
.from(simple)
.all();
assert!(result[0].result.len() == 4);
assert!(result[0].result.starts_with("20")); }
#[derive(Debug, SQLiteFromRow)]
struct InferredDateResult {
today: String,
}
#[drizzle::test]
fn test_inferred_current_date(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
db.insert(simple)
.values([InsertSimple::new("seed")])
.execute();
let result: Vec<InferredDateResult> = db
.select(alias(
cast(current_date(), drizzle::sqlite::types::Text),
"today",
))
.from(simple)
.all();
assert_eq!(result.len(), 1);
assert_eq!(result[0].today.len(), 10);
assert!(result[0].today.contains('-'));
}
#[derive(Debug, SQLiteFromRow)]
struct InferredTimestampResult {
now: String,
}
#[drizzle::test]
fn test_inferred_current_timestamp(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
db.insert(simple)
.values([InsertSimple::new("seed")])
.execute();
let result: Vec<InferredTimestampResult> = db
.select(alias(
cast(current_timestamp(), drizzle::sqlite::types::Text),
"now",
))
.from(simple)
.all();
assert_eq!(result.len(), 1);
assert!(result[0].now.contains(' '));
assert!(result[0].now.contains(':'));
}
#[derive(Debug, SQLiteFromRow)]
struct CaseNonNullResult {
label: String,
}
#[derive(Debug, SQLiteFromRow)]
struct CaseNullableResult {
label: Option<String>,
}
#[drizzle::test]
fn test_case_when_with_else(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(10),
InsertSimple::new("bob").with_id(25),
InsertSimple::new("charlie").with_id(70),
];
db.insert(simple).values(test_data).execute();
let results: Vec<CaseNonNullResult> = db
.select(alias(
case()
.when(gt(simple.id, 65), "Senior")
.when(gt(simple.id, 18), "Adult")
.r#else("Minor"),
"label",
))
.from(simple)
.order_by(asc(simple.id))
.all();
assert_eq!(results.len(), 3);
assert_eq!(results[0].label, "Minor"); assert_eq!(results[1].label, "Adult"); assert_eq!(results[2].label, "Senior"); }
#[drizzle::test]
fn test_case_when_no_else(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(10),
InsertSimple::new("bob").with_id(25),
];
db.insert(simple).values(test_data).execute();
let results: Vec<CaseNullableResult> = db
.select(alias(case().when(gt(simple.id, 20), "Big").end(), "label"))
.from(simple)
.order_by(asc(simple.id))
.all();
assert_eq!(results.len(), 2);
assert_eq!(results[0].label, None); assert_eq!(results[1].label.as_deref(), Some("Big")); }
#[derive(Debug, SQLiteFromRow)]
struct RowNumberResult {
name: String,
rn: i64,
}
#[drizzle::test]
fn test_window_row_number(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(1),
InsertSimple::new("bob").with_id(2),
InsertSimple::new("charlie").with_id(3),
];
db.insert(simple).values(test_data).execute();
let results: Vec<RowNumberResult> = db
.select((
simple.name,
alias(row_number().over(window().order_by(asc(simple.id))), "rn"),
))
.from(simple)
.all();
assert_eq!(results.len(), 3);
assert_eq!(results[0].name, "alice");
assert_eq!(results[0].rn, 1);
assert_eq!(results[1].name, "bob");
assert_eq!(results[1].rn, 2);
assert_eq!(results[2].name, "charlie");
assert_eq!(results[2].rn, 3);
}
#[derive(Debug, SQLiteFromRow)]
struct RunningSumResult {
name: String,
running_total: Option<i32>,
}
#[drizzle::test]
fn test_window_sum_over(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(10),
InsertSimple::new("bob").with_id(20),
InsertSimple::new("charlie").with_id(30),
];
db.insert(simple).values(test_data).execute();
let results: Vec<RunningSumResult> = db
.select((
simple.name,
alias(
sum(simple.id).over(
window()
.order_by(asc(simple.id))
.rows_between(FrameBound::UnboundedPreceding, FrameBound::CurrentRow),
),
"running_total",
),
))
.from(simple)
.all();
assert_eq!(results.len(), 3);
assert_eq!(results[0].name, "alice");
assert_eq!(results[0].running_total, Some(10)); assert_eq!(results[1].name, "bob");
assert_eq!(results[1].running_total, Some(30)); assert_eq!(results[2].name, "charlie");
assert_eq!(results[2].running_total, Some(60)); }
#[derive(Debug, SQLiteFromRow)]
struct RankResult {
name: String,
rnk: i64,
}
#[drizzle::test]
fn test_window_dense_rank(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(1),
InsertSimple::new("bob").with_id(2),
InsertSimple::new("charlie").with_id(3),
];
db.insert(simple).values(test_data).execute();
let results: Vec<RankResult> = db
.select((
simple.name,
alias(dense_rank().over(window().order_by(asc(simple.id))), "rnk"),
))
.from(simple)
.order_by(asc(simple.id))
.all();
assert_eq!(results.len(), 3);
assert_eq!(results[0].name, "alice");
assert_eq!(results[0].rnk, 1);
assert_eq!(results[1].name, "bob");
assert_eq!(results[1].rnk, 2);
assert_eq!(results[2].name, "charlie");
assert_eq!(results[2].rnk, 3);
}
#[derive(Debug, SQLiteFromRow)]
struct PercentRankResult {
name: String,
pct: f64,
}
#[drizzle::test]
fn test_window_percent_rank(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(1),
InsertSimple::new("bob").with_id(2),
InsertSimple::new("charlie").with_id(3),
];
db.insert(simple).values(test_data).execute();
let results: Vec<PercentRankResult> = db
.select((
simple.name,
alias(
percent_rank().over(window().order_by(asc(simple.id))),
"pct",
),
))
.from(simple)
.all();
assert_eq!(results.len(), 3);
assert_eq!(results[0].name, "alice");
assert!((results[0].pct - 0.0).abs() < f64::EPSILON); assert!((results[1].pct - 0.5).abs() < f64::EPSILON); assert!((results[2].pct - 1.0).abs() < f64::EPSILON); }
#[derive(Debug, SQLiteFromRow)]
struct CumeDistResult {
name: String,
cd: f64,
}
#[drizzle::test]
fn test_window_cume_dist(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(1),
InsertSimple::new("bob").with_id(2),
InsertSimple::new("charlie").with_id(3),
];
db.insert(simple).values(test_data).execute();
let results: Vec<CumeDistResult> = db
.select((
simple.name,
alias(cume_dist().over(window().order_by(asc(simple.id))), "cd"),
))
.from(simple)
.all();
assert_eq!(results.len(), 3);
assert_eq!(results[0].name, "alice");
assert!((results[0].cd - 1.0 / 3.0).abs() < f64::EPSILON); assert!((results[1].cd - 2.0 / 3.0).abs() < f64::EPSILON); assert!((results[2].cd - 1.0).abs() < f64::EPSILON); }
#[drizzle::test]
fn test_concat_ws(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![InsertSimple::new("World").with_id(1)];
db.insert(simple).values(test_data).execute();
let result: Vec<StringResult> = db
.select(alias(concat_ws(", ", ["Hello", "Beautiful"]), "result"))
.from(simple)
.all();
assert_eq!(result[0].result, "Hello, Beautiful");
}
#[derive(Debug, SQLiteFromRow)]
struct BoolIntResult {
result: i64,
}
#[drizzle::test]
fn test_is_distinct_from(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(10),
InsertSimple::new("bob").with_id(20),
];
db.insert(simple).values(test_data).execute();
let result: Vec<BoolIntResult> = db
.select(alias(
cast(
is_distinct_from(simple.id, 10),
drizzle::sqlite::types::Integer,
),
"result",
))
.from(simple)
.r#where(eq(simple.id, 10))
.all();
assert_eq!(result[0].result, 0);
let result: Vec<BoolIntResult> = db
.select(alias(
cast(
is_distinct_from(simple.id, 20),
drizzle::sqlite::types::Integer,
),
"result",
))
.from(simple)
.r#where(eq(simple.id, 10))
.all();
assert_eq!(result[0].result, 1);
let result: Vec<BoolIntResult> = db
.select(alias(
cast(
is_not_distinct_from(simple.id, 10),
drizzle::sqlite::types::Integer,
),
"result",
))
.from(simple)
.r#where(eq(simple.id, 10))
.all();
assert_eq!(result[0].result, 1);
}
#[drizzle::test]
fn test_is_true_is_false(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("truthy").with_id(1),
InsertSimple::new("falsy").with_id(0),
];
db.insert(simple).values(test_data).execute();
let result: Vec<BoolIntResult> = db
.select(alias(
cast(is_true(gt(simple.id, 0)), drizzle::sqlite::types::Integer),
"result",
))
.from(simple)
.r#where(eq(simple.name, "truthy"))
.all();
assert_eq!(result[0].result, 1);
let result: Vec<BoolIntResult> = db
.select(alias(
cast(is_true(gt(simple.id, 0)), drizzle::sqlite::types::Integer),
"result",
))
.from(simple)
.r#where(eq(simple.name, "falsy"))
.all();
assert_eq!(result[0].result, 0);
let result: Vec<BoolIntResult> = db
.select(alias(
cast(is_false(gt(simple.id, 0)), drizzle::sqlite::types::Integer),
"result",
))
.from(simple)
.r#where(eq(simple.name, "falsy"))
.all();
assert_eq!(result[0].result, 1);
}
#[derive(Debug, SQLiteFromRow)]
struct TotalResult {
total: f64,
}
#[drizzle::test]
fn test_total_aggregate(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("a").with_id(10),
InsertSimple::new("b").with_id(20),
InsertSimple::new("c").with_id(30),
];
db.insert(simple).values(test_data).execute();
let result: Vec<TotalResult> = db
.select(alias(total(simple.id), "total"))
.from(simple)
.r#where(eq(simple.id, 999))
.all();
assert_eq!(result[0].total, 0.0);
let result: Vec<TotalResult> = db
.select(alias(total(simple.id), "total"))
.from(simple)
.all();
assert_eq!(result[0].total, 60.0);
}
#[drizzle::test]
fn test_char_length(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("hello").with_id(1),
InsertSimple::new("").with_id(2),
];
db.insert(simple).values(test_data).execute();
let result: Vec<LengthResult> = db
.select(alias(char_length(simple.name), "length"))
.from(simple)
.r#where(eq(simple.id, 1))
.all();
assert_eq!(result[0].length, 5);
let result: Vec<LengthResult> = db
.select(alias(char_length(simple.name), "length"))
.from(simple)
.r#where(eq(simple.id, 2))
.all();
assert_eq!(result[0].length, 0);
}
#[drizzle::test]
fn test_octet_length(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![InsertSimple::new("hello").with_id(1)];
db.insert(simple).values(test_data).execute();
let result: Vec<LengthResult> = db
.select(alias(octet_length(simple.name), "length"))
.from(simple)
.all();
assert_eq!(result[0].length, 5);
}
#[derive(Debug, SQLiteFromRow)]
struct RandomIntResult {
result: i64,
}
#[drizzle::test]
fn test_random(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![InsertSimple::new("seed").with_id(1)];
db.insert(simple).values(test_data).execute();
let result: Vec<RandomIntResult> = db.select(alias(random(), "result")).from(simple).all();
assert_eq!(result.len(), 1);
let _ = result[0].result;
}
#[drizzle::test]
fn test_timediff(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![InsertSimple::new("seed").with_id(1)];
db.insert(simple).values(test_data).execute();
let result: Vec<StringResult> = db
.select(alias(
timediff(
cast("2024-01-02", drizzle::sqlite::types::Text),
cast("2024-01-01", drizzle::sqlite::types::Text),
),
"result",
))
.from(simple)
.all();
assert!(result[0].result.contains("1"));
}