#![allow(missing_docs)]
use rusqlite::Connection;
fn explain(conn: &Connection, sql: &str) -> Vec<String> {
let explain_sql = format!("EXPLAIN QUERY PLAN {sql}");
let mut stmt = conn.prepare(&explain_sql).expect("EXPLAIN prepare must succeed");
let rows = stmt
.query_map([], |row| row.get::<_, String>(3))
.expect("EXPLAIN query must succeed");
rows.map(|r| r.expect("row must decode")).collect()
}
#[test]
fn list_predicates_uses_index_no_cutoff() {
let conn = mempill_sqlite::connection::open_in_memory()
.expect("in-memory SQLite must open");
let plan = explain(
&conn,
"SELECT DISTINCT predicate FROM claims WHERE agent_id = 'a' AND subject = 's'",
);
let plan_text = plan.join("\n");
assert!(
plan_text.contains("idx_claims_subject_line"),
"DISTINCT predicate query (no cutoff) must use idx_claims_subject_line; \
got plan:\n{plan_text}"
);
assert!(
!plan_text.to_ascii_uppercase().contains("TEMP B-TREE"),
"DISTINCT predicate query (no cutoff) must NOT require a TEMP B-TREE; \
the DISTINCT is served by the index prefix (agent_id, subject, predicate); \
got plan:\n{plan_text}"
);
}
#[test]
fn list_predicates_uses_index_with_cutoff() {
let conn = mempill_sqlite::connection::open_in_memory()
.expect("in-memory SQLite must open");
let plan = explain(
&conn,
"SELECT DISTINCT predicate FROM claims WHERE agent_id = 'a' AND subject = 's' AND tx_time <= '2030-01-01T00:00:00+00:00'",
);
let plan_text = plan.join("\n");
assert!(
plan_text.contains("idx_claims_subject_line"),
"DISTINCT predicate query (with cutoff) must use idx_claims_subject_line; \
got plan:\n{plan_text}"
);
assert!(
!plan_text.to_ascii_uppercase().contains("SCAN claims"),
"DISTINCT predicate query (with cutoff) must NOT full-scan the claims table; \
it must use the index; got plan:\n{plan_text}"
);
}