#![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, SimpleSchema};
use drizzle::core::expr::*;
use drizzle::sqlite::prelude::*;
#[derive(Debug, SQLiteFromRow)]
struct GroupCountResult {
name: String,
count: i64,
}
#[derive(Debug, SQLiteFromRow)]
struct PkGroupResult {
id: i32,
name: String,
count: i64,
}
#[derive(Debug, SQLiteFromRow)]
struct BoolGroupResult {
active: bool,
total: Option<i32>,
}
#[cfg(feature = "uuid")]
#[derive(Debug, SQLiteFromRow)]
struct GroupAvgResult {
active: bool,
avg_score: Option<f64>,
}
#[drizzle::test]
fn test_group_by_simple_count(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(1),
InsertSimple::new("alice").with_id(2),
InsertSimple::new("bob").with_id(3),
InsertSimple::new("bob").with_id(4),
InsertSimple::new("bob").with_id(5),
];
db.insert(simple).values(test_data).execute();
let results: Vec<GroupCountResult> = db
.select((simple.name, alias(count(simple.id), "count")))
.from(simple)
.group_by(simple.name)
.order_by(asc(simple.name))
.all();
assert_eq!(results.len(), 2);
assert_eq!(results[0].name, "alice");
assert_eq!(results[0].count, 2);
assert_eq!(results[1].name, "bob");
assert_eq!(results[1].count, 3);
}
#[drizzle::test]
fn test_group_by_primary_key_functional_dependency(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(1),
InsertSimple::new("bob").with_id(2),
];
db.insert(simple).values(test_data).execute();
let results: Vec<PkGroupResult> = db
.select((simple.id, simple.name, alias(count(simple.id), "count")))
.from(simple)
.group_by(simple.id)
.order_by(asc(simple.id))
.all();
assert_eq!(results.len(), 2);
assert_eq!(results[0].id, 1);
assert_eq!(results[0].name, "alice");
assert_eq!(results[0].count, 1);
assert_eq!(results[1].id, 2);
assert_eq!(results[1].name, "bob");
assert_eq!(results[1].count, 1);
}
#[cfg(feature = "uuid")]
#[drizzle::test]
fn test_group_by_with_sum(db: &mut TestDb<ComplexSchema>) {
let ComplexSchema { complex } = schema;
let test_data = vec![
InsertComplex::new("alice", true, Role::User).with_age(25),
InsertComplex::new("bob", true, Role::Admin).with_age(30),
InsertComplex::new("charlie", false, Role::User).with_age(35),
InsertComplex::new("diana", false, Role::User).with_age(40),
];
db.insert(complex).values(test_data).execute();
let results: Vec<BoolGroupResult> = db
.select((complex.active, alias(sum(complex.age), "total")))
.from(complex)
.group_by(complex.active)
.order_by(asc(complex.active))
.all();
assert_eq!(results.len(), 2);
assert!(!results[0].active);
assert_eq!(results[0].total, Some(75)); assert!(results[1].active);
assert_eq!(results[1].total, Some(55)); }
#[cfg(feature = "uuid")]
#[drizzle::test]
fn test_group_by_with_avg(db: &mut TestDb<ComplexSchema>) {
let ComplexSchema { complex } = schema;
let test_data = vec![
InsertComplex::new("alice", true, Role::User).with_score(80.0),
InsertComplex::new("bob", true, Role::Admin).with_score(90.0),
InsertComplex::new("charlie", false, Role::User).with_score(70.0),
InsertComplex::new("diana", false, Role::User).with_score(60.0),
];
db.insert(complex).values(test_data).execute();
let results: Vec<GroupAvgResult> = db
.select((complex.active, alias(avg(complex.score), "avg_score")))
.from(complex)
.group_by(complex.active)
.order_by(asc(complex.active))
.all();
assert_eq!(results.len(), 2);
assert!(!results[0].active);
assert!((results[0].avg_score.unwrap() - 65.0).abs() < 0.01);
assert!(results[1].active);
assert!((results[1].avg_score.unwrap() - 85.0).abs() < 0.01);
}
#[drizzle::test]
fn test_having_filters_groups(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(1),
InsertSimple::new("alice").with_id(2),
InsertSimple::new("alice").with_id(3),
InsertSimple::new("bob").with_id(4),
];
db.insert(simple).values(test_data).execute();
let results: Vec<GroupCountResult> = db
.select((simple.name, alias(count(simple.id), "count")))
.from(simple)
.group_by(simple.name)
.having(gt(count(simple.id), 2_i64))
.all();
assert_eq!(results.len(), 1);
assert_eq!(results[0].name, "alice");
assert_eq!(results[0].count, 3);
}
#[drizzle::test]
fn test_having_with_sum(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(10),
InsertSimple::new("alice").with_id(20),
InsertSimple::new("bob").with_id(5),
];
db.insert(simple).values(test_data).execute();
#[derive(Debug, SQLiteFromRow)]
struct SumGroupResult {
name: String,
total: Option<i32>,
}
let results: Vec<SumGroupResult> = db
.select((simple.name, alias(sum(simple.id), "total")))
.from(simple)
.group_by(simple.name)
.having(gt(sum(simple.id), 10))
.all();
assert_eq!(results.len(), 1);
assert_eq!(results[0].name, "alice");
assert_eq!(results[0].total, Some(30));
}
#[drizzle::test]
fn test_having_no_matching_groups(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(1),
InsertSimple::new("bob").with_id(2),
];
db.insert(simple).values(test_data).execute();
let results: Vec<GroupCountResult> = db
.select((simple.name, alias(count(simple.id), "count")))
.from(simple)
.group_by(simple.name)
.having(gt(count(simple.id), 10_i64))
.all();
assert_eq!(results.len(), 0);
}
#[drizzle::test]
fn test_group_by_order_by_aggregate(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(10),
InsertSimple::new("alice").with_id(20),
InsertSimple::new("bob").with_id(100),
InsertSimple::new("charlie").with_id(1),
];
db.insert(simple).values(test_data).execute();
#[derive(Debug, SQLiteFromRow)]
struct SumGroupResult {
name: String,
total: Option<i32>,
}
let results: Vec<SumGroupResult> = db
.select((simple.name, alias(sum(simple.id), "total")))
.from(simple)
.group_by(simple.name)
.order_by(desc(sum(simple.id)))
.all();
assert_eq!(results.len(), 3);
assert_eq!(results[0].name, "bob");
assert_eq!(results[0].total, Some(100));
assert_eq!(results[1].name, "alice");
assert_eq!(results[1].total, Some(30));
assert_eq!(results[2].name, "charlie");
assert_eq!(results[2].total, Some(1));
}
#[drizzle::test]
fn test_group_by_with_limit(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("bob").with_id(3),
InsertSimple::new("charlie").with_id(4),
InsertSimple::new("charlie").with_id(5),
InsertSimple::new("charlie").with_id(6),
];
db.insert(simple).values(test_data).execute();
let results: Vec<GroupCountResult> = db
.select((simple.name, alias(count(simple.id), "count")))
.from(simple)
.group_by(simple.name)
.order_by(desc(count(simple.id)))
.limit(2)
.all();
assert_eq!(results.len(), 2);
assert_eq!(results[0].name, "charlie");
assert_eq!(results[0].count, 3);
assert_eq!(results[1].name, "bob");
assert_eq!(results[1].count, 2);
}
#[drizzle::test]
fn test_group_by_limit_without_order(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let test_data = vec![
InsertSimple::new("alice").with_id(1),
InsertSimple::new("alice").with_id(2),
InsertSimple::new("bob").with_id(3),
InsertSimple::new("charlie").with_id(4),
];
db.insert(simple).values(test_data).execute();
let results: Vec<GroupCountResult> = db
.select((simple.name, alias(count(simple.id), "count")))
.from(simple)
.group_by(simple.name)
.limit(2)
.all();
assert_eq!(results.len(), 2);
}
#[drizzle::test]
fn test_select_from_offset(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("diana").with_id(4),
InsertSimple::new("eve").with_id(5),
];
db.insert(simple).values(test_data).execute();
#[derive(Debug, SQLiteFromRow)]
struct NameResult {
name: String,
}
let results: Vec<NameResult> = db
.select(simple.name)
.from(simple)
.order_by(asc(simple.id))
.limit(2)
.offset(2)
.all();
assert_eq!(results.len(), 2);
assert_eq!(results[0].name, "charlie");
assert_eq!(results[1].name, "diana");
}
#[drizzle::test]
fn test_group_by_empty_table(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let results: Vec<GroupCountResult> = db
.select((simple.name, alias(count(simple.id), "count")))
.from(simple)
.group_by(simple.name)
.all();
assert_eq!(results.len(), 0);
}
#[derive(Debug, SQLiteFromRow)]
struct NameResult {
name: String,
}
#[drizzle::test]
fn test_union_via_drizzle_builder(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<NameResult> = db
.select(simple.name)
.from(simple)
.r#where(lte(simple.id, 2))
.union(
db.select(simple.name)
.from(simple)
.r#where(gte(simple.id, 2)),
)
.order_by(asc(simple.name))
.all();
assert_eq!(results.len(), 3);
assert_eq!(results[0].name, "alice");
assert_eq!(results[1].name, "bob");
assert_eq!(results[2].name, "charlie");
}
#[drizzle::test]
fn test_union_all_preserves_duplicates(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<NameResult> = db
.select(simple.name)
.from(simple)
.r#where(lte(simple.id, 2))
.union_all(
db.select(simple.name)
.from(simple)
.r#where(gte(simple.id, 2)),
)
.order_by(asc(simple.name))
.all();
assert_eq!(results.len(), 4);
assert_eq!(results[0].name, "alice");
assert_eq!(results[1].name, "bob");
assert_eq!(results[2].name, "bob");
assert_eq!(results[3].name, "charlie");
}
#[drizzle::test]
fn test_union_mixed_drizzle_and_raw(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 qb = drizzle_sqlite::builder::QueryBuilder::new::<SimpleSchema>();
let results: Vec<NameResult> = db
.select(simple.name)
.from(simple)
.r#where(eq(simple.id, 1))
.union(
qb.select(simple.name)
.from(simple)
.r#where(eq(simple.id, 3)),
)
.order_by(asc(simple.name))
.all();
assert_eq!(results.len(), 2);
assert_eq!(results[0].name, "alice");
assert_eq!(results[1].name, "charlie");
}
#[drizzle::test]
fn test_chained_set_operations(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<NameResult> = db
.select(simple.name)
.from(simple)
.r#where(eq(simple.id, 1))
.union(
db.select(simple.name)
.from(simple)
.r#where(eq(simple.id, 2)),
)
.union_all(
db.select(simple.name)
.from(simple)
.r#where(eq(simple.id, 1)),
)
.order_by(asc(simple.name))
.all();
assert_eq!(results.len(), 3);
assert_eq!(results[0].name, "alice");
assert_eq!(results[1].name, "alice");
assert_eq!(results[2].name, "bob");
}
#[drizzle::test]
fn test_set_op_with_order_limit(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("diana").with_id(4),
];
db.insert(simple).values(test_data).execute();
let results: Vec<NameResult> = db
.select(simple.name)
.from(simple)
.r#where(lte(simple.id, 2))
.union(
db.select(simple.name)
.from(simple)
.r#where(gte(simple.id, 3)),
)
.order_by(desc(simple.name))
.limit(2)
.all();
assert_eq!(results.len(), 2);
assert_eq!(results[0].name, "diana");
assert_eq!(results[1].name, "charlie");
}
#[drizzle::test]
fn test_intersect_via_drizzle_builder(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<NameResult> = db
.select(simple.name)
.from(simple)
.r#where(lte(simple.id, 2))
.intersect(
db.select(simple.name)
.from(simple)
.r#where(gte(simple.id, 2)),
)
.all();
assert_eq!(results.len(), 1);
assert_eq!(results[0].name, "bob");
}
#[drizzle::test]
fn test_except_via_drizzle_builder(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<NameResult> = db
.select(simple.name)
.from(simple)
.r#where(lte(simple.id, 2))
.except(
db.select(simple.name)
.from(simple)
.r#where(gte(simple.id, 2)),
)
.all();
assert_eq!(results.len(), 1);
assert_eq!(results[0].name, "alice");
}