#[path = "common/harness.rs"]
mod harness;
#[path = "common/plan_fixture.rs"]
mod plan_fixture;
use harness::TestHarness;
use libsql::Builder;
use macrame::prelude::*;
use plan_fixture::{counts, counts_of};
const TS: &str = "2026-01-01T00:00:00.000000Z";
const VALID_AT: &str = "2026-06-01T00:00:00.000000Z";
const RECORDED_AT: &str = "2026-06-01T00:00:00.000000Z";
const HUB_EDGES: usize = 150;
const LEAF_EDGES: usize = 60;
const CONCEPTS: usize = 260;
async fn written_and_analysed(harness: &TestHarness) -> libsql::Connection {
let db = Database::open_with_cadence(&harness.db_path, None)
.await
.unwrap();
let concepts: Vec<ConceptUpsert> = (0..CONCEPTS)
.map(|i| ConceptUpsert::new(format!("c{i:04}"), "N").valid_from(TS))
.collect();
db.write_concepts(concepts).await.unwrap();
let mut edges = Vec::new();
for i in 1..=HUB_EDGES {
edges.push(EdgeAssertion::new("c0000", format!("c{i:04}"), "LINKS").valid_from(TS));
}
for i in (HUB_EDGES + 1)..=(HUB_EDGES + LEAF_EDGES) {
edges.push(
EdgeAssertion::new(format!("c{i:04}"), format!("c{:04}", i + 1), "LINKS")
.valid_from(TS),
);
}
db.write_bulk_atomic(edges).await.unwrap();
db.analyze().await.unwrap();
db.close().await.unwrap();
Builder::new_local(&harness.db_path)
.build()
.await
.unwrap()
.connect()
.unwrap()
}
async fn plan_of(conn: &libsql::Connection, sql: &str) -> String {
let mut rows = conn
.query(&format!("EXPLAIN QUERY PLAN {sql}"), ())
.await
.unwrap();
let mut lines = Vec::new();
while let Some(r) = rows.next().await.unwrap() {
lines.push(r.get::<String>(3).unwrap());
}
lines.join(" | ")
}
fn walk() -> TraversalBuilder {
TraversalBuilder::new("c0000").max_depth(2)
}
#[tokio::test]
async fn a_transaction_time_read_seeks_rather_than_scans() {
let harness = TestHarness::new();
let conn = written_and_analysed(&harness).await;
let mut rows = conn
.query("SELECT COUNT(*) FROM transaction_log", ())
.await
.unwrap();
let logged: i64 = rows.next().await.unwrap().unwrap().get(0).unwrap();
assert!(
logged > 100,
"the fixture logged {logged} rows, which is too few for a plan on this \
table to mean anything"
);
let plan = plan_of(&conn, &walk().as_of_recorded(RECORDED_AT).build_sql()).await;
assert!(
plan.contains("SEARCH transaction_log USING INDEX idx_txlog_time"),
"the transaction-time bound stopped seeking, which is the one arm of \
F-33 that was already answered: {plan}"
);
}
#[tokio::test]
async fn adding_the_valid_instant_does_not_reach_the_plan() {
let harness = TestHarness::new();
let conn = written_and_analysed(&harness).await;
let recorded_only = plan_of(&conn, &walk().as_of_recorded(RECORDED_AT).build_sql()).await;
let both = plan_of(
&conn,
&walk()
.as_of_valid(VALID_AT)
.as_of_recorded(RECORDED_AT)
.build_sql(),
)
.await;
assert_eq!(
both, recorded_only,
"the valid-time instant now reaches the plan. That is not a regression \
— it means the two axes have started meeting somewhere indexable, \
and F-33's decision (D-196: nothing to build) is due for review"
);
let valid_only = plan_of(&conn, &walk().as_of_valid(VALID_AT).build_sql()).await;
assert_ne!(
valid_only, recorded_only,
"the premise has stopped holding: all three arms now plan alike, so \
this test could not tell an ignored instant from a relocated one"
);
}
#[tokio::test]
async fn a_two_dimensional_candidate_is_used_as_a_one_dimensional_one() {
let harness = TestHarness::new();
let conn = written_and_analysed(&harness).await;
let sql = walk()
.as_of_valid(VALID_AT)
.as_of_recorded(RECORDED_AT)
.build_sql();
let before = plan_of(&conn, &sql).await;
conn.execute(
"CREATE INDEX probe_txlog_two_d ON transaction_log \
(recorded_at, json_extract(payload, '$.valid_from'))",
(),
)
.await
.unwrap();
let _ = conn.query("ANALYZE", ()).await.unwrap();
let after = plan_of(&conn, &sql).await;
assert!(
after.contains("USING INDEX probe_txlog_two_d (recorded_at<?)"),
"the candidate index is either unused or used on more than its leading \
column. Either way D-196's arithmetic changes and F-33 wants \
re-opening: {after}"
);
assert_eq!(
after.replace("probe_txlog_two_d", "idx_txlog_time"),
before,
"the two-dimensional candidate changed the shape of the plan and not \
just the name of the index it seeks on, which is the outcome D-196 \
measured as not happening"
);
}
#[tokio::test]
async fn a_cross_axis_read_costs_what_the_transaction_time_read_costs() {
let harness = TestHarness::new();
let conn = written_and_analysed(&harness).await;
let valid_only = counts_of(&conn, &walk().as_of_valid(VALID_AT).build_sql()).await;
let recorded_only = counts_of(&conn, &walk().as_of_recorded(RECORDED_AT).build_sql()).await;
let both = counts_of(
&conn,
&walk()
.as_of_valid(VALID_AT)
.as_of_recorded(RECORDED_AT)
.build_sql(),
)
.await;
assert_eq!(
valid_only,
counts(3, 2, 1),
"the valid-time-only arm moved. It is the control here: if it stops \
differing from the transaction-time arm, the equality this test \
asserts below stops meaning anything"
);
assert_eq!(
recorded_only,
counts(4, 2, 5),
"the transaction-time read's cost moved. Re-run \
`cargo run --example bitemporal_index_probe` and read the sweep \
before changing this number (D-195)"
);
assert_eq!(
both, recorded_only,
"stating a valid instant as well as a transaction instant now costs \
something. F-33 closed as *no index* because the two axes never meet \
on a table and the second bound reaches no access path; a difference \
here means that is no longer true and D-196 is due for review"
);
}