use spg_engine::{Engine, QueryResult};
use spg_storage::Value;
fn rows(e: &mut Engine, sql: &str) -> Vec<Vec<Value<'static>>> {
let r = e
.execute(sql)
.unwrap_or_else(|err| panic!("{sql}: {err:?}"));
let QueryResult::Rows { rows, .. } = r else {
panic!("expected Rows for {sql}");
};
rows.into_iter().map(|r| r.values).collect()
}
fn one_i64(e: &mut Engine, sql: &str) -> i64 {
let mut rs = rows(e, sql);
let row = rs.pop().expect("one row");
match row.into_iter().next().expect("one col") {
Value::BigInt(n) => n,
Value::Int(n) => i64::from(n),
other => panic!("expected integer, got {other:?}"),
}
}
fn list_setup() -> Engine {
let mut e = Engine::new();
e.execute(
"CREATE TABLE cust (
id BIGINT,
region TEXT
) PARTITION BY LIST (region)",
)
.unwrap();
e.execute("CREATE TABLE cust_apac PARTITION OF cust FOR VALUES IN ('jp', 'kr', 'tw')")
.unwrap();
e.execute("CREATE TABLE cust_emea PARTITION OF cust FOR VALUES IN ('de', 'fr', 'uk')")
.unwrap();
e.execute("CREATE TABLE cust_default PARTITION OF cust DEFAULT")
.unwrap();
for (id, region) in [
(1, "jp"),
(2, "kr"),
(3, "de"),
(4, "fr"),
(5, "us"), (6, "br"), ] {
let sql = format!("INSERT INTO cust VALUES ({id}, '{region}')");
e.execute(&sql).unwrap();
}
e
}
#[test]
fn list_eq_predicate_returns_only_matching_partition_rows() {
let mut e = list_setup();
let rs = rows(&mut e, "SELECT id FROM cust WHERE region = 'jp'");
assert_eq!(rs.len(), 1);
assert!(matches!(rs[0][0], Value::BigInt(1)));
let rs = rows(&mut e, "SELECT id FROM cust WHERE region = 'fr'");
assert_eq!(rs.len(), 1);
assert!(matches!(rs[0][0], Value::BigInt(4)));
let rs = rows(&mut e, "SELECT id FROM cust WHERE region = 'us'");
assert_eq!(rs.len(), 1);
assert!(matches!(rs[0][0], Value::BigInt(5)));
}
#[test]
fn list_no_predicate_returns_every_partition_row() {
let mut e = list_setup();
assert_eq!(one_i64(&mut e, "SELECT COUNT(*) FROM cust"), 6);
}
#[test]
fn list_eq_on_unmatched_value_still_returns_default_rows() {
let mut e = list_setup();
let count = one_i64(&mut e, "SELECT COUNT(*) FROM cust WHERE region = 'us'");
assert_eq!(count, 1);
}
fn hash_setup() -> Engine {
let mut e = Engine::new();
e.execute("CREATE TABLE oh (id BIGINT, label TEXT) PARTITION BY HASH (id)")
.unwrap();
for r in 0..4 {
let sql = format!(
"CREATE TABLE oh_{r} PARTITION OF oh FOR VALUES WITH (MODULUS 4, REMAINDER {r})"
);
e.execute(&sql).unwrap();
}
for i in 0..100 {
let sql = format!("INSERT INTO oh VALUES ({i}, 'r{i}')");
e.execute(&sql).unwrap();
}
e
}
#[test]
fn hash_eq_predicate_returns_unique_row() {
let mut e = hash_setup();
let rs = rows(&mut e, "SELECT id, label FROM oh WHERE id = 42");
assert_eq!(rs.len(), 1);
assert!(matches!(rs[0][0], Value::BigInt(42)));
}
#[test]
fn hash_eq_predicate_consistent_with_total_count() {
let mut e = hash_setup();
let mut sum = 0;
for i in 0..100 {
let sql = format!("SELECT COUNT(*) FROM oh WHERE id = {i}");
sum += one_i64(&mut e, &sql);
}
assert_eq!(sum, 100);
}
#[test]
fn spg_partition_health_lists_parent_and_every_child() {
let mut e = list_setup();
let rs = rows(&mut e, "SELECT * FROM spg_partition_health");
assert_eq!(rs.len(), 4);
let names_roles: Vec<(String, String)> = rs
.iter()
.map(|r| {
let Value::Text(n) = &r[1] else {
panic!("name")
};
let Value::Text(role) = &r[2] else {
panic!("role")
};
(n.to_string(), role.to_string())
})
.collect();
assert!(
names_roles
.iter()
.any(|(n, role)| n == "cust" && role == "Parent")
);
assert!(
names_roles
.iter()
.any(|(n, role)| n == "cust_apac" && role == "List")
);
assert!(
names_roles
.iter()
.any(|(n, role)| n == "cust_emea" && role == "List")
);
assert!(
names_roles
.iter()
.any(|(n, role)| n == "cust_default" && role == "Default")
);
let total_leaf_rows: i64 = rs
.iter()
.filter(|r| {
let Value::Text(role) = &r[2] else {
return false;
};
role.as_ref() != "Parent"
})
.map(|r| match r[3] {
Value::BigInt(n) => n,
_ => 0,
})
.sum();
assert_eq!(total_leaf_rows, 6);
}
#[test]
fn range_eq_predicate_still_prunes_correctly() {
let mut e = Engine::new();
e.execute(
"CREATE TABLE events (
id BIGINT,
received_at TIMESTAMPTZ
) PARTITION BY RANGE (received_at)",
)
.unwrap();
e.execute(
"CREATE TABLE events_2026_06 PARTITION OF events \
FOR VALUES FROM ('2026-06-01 00:00:00+00') TO ('2026-07-01 00:00:00+00')",
)
.unwrap();
e.execute(
"CREATE TABLE events_2026_07 PARTITION OF events \
FOR VALUES FROM ('2026-07-01 00:00:00+00') TO ('2026-08-01 00:00:00+00')",
)
.unwrap();
e.execute("CREATE TABLE events_default PARTITION OF events DEFAULT")
.unwrap();
e.execute("INSERT INTO events VALUES (1, '2026-06-15 12:00:00+00')")
.unwrap();
e.execute("INSERT INTO events VALUES (2, '2026-07-15 12:00:00+00')")
.unwrap();
let count = one_i64(
&mut e,
"SELECT COUNT(*) FROM events WHERE received_at >= '2026-07-01 00:00:00+00'",
);
assert_eq!(count, 1);
}