#![allow(dead_code)]
use libsql::Builder;
use macrame::schema::ddl;
pub const TS: &str = "2026-01-01T00:00:00.000000Z";
pub const OPEN: &str = "9999-12-31T23:59:59.999999Z";
pub const HUB_EDGES: usize = 150;
pub const LEAF_EDGES: usize = 60;
pub const CONCEPTS: usize = 260;
pub async fn migrated(db_path: &std::path::Path) -> libsql::Connection {
let db = Builder::new_local(db_path).build().await.unwrap();
let conn = db.connect().unwrap();
macrame::schema::run_migrations(&conn).await.unwrap();
conn
}
pub async fn populated_and_analysed(db_path: &std::path::Path) -> libsql::Connection {
let conn = populated_without_statistics(db_path).await;
let _ = conn.query(ddl::ANALYZE, ()).await.unwrap();
conn
}
pub async fn populated_without_statistics(db_path: &std::path::Path) -> libsql::Connection {
let conn = migrated(db_path).await;
let _ = conn.query(ddl::ANALYSIS_LIMIT, ()).await.unwrap();
conn.execute("BEGIN", ()).await.unwrap();
for i in 0..CONCEPTS {
conn.execute(
"INSERT INTO concepts (id, title, content, valid_from, valid_to, \
recorded_at, retired) VALUES (?1, ?2, '', ?3, ?4, ?3, 0)",
libsql::params![format!("c{i:04}"), format!("C{i}"), TS, OPEN],
)
.await
.unwrap();
}
for i in 1..=HUB_EDGES {
insert_edge(&conn, "c0000", &format!("c{i:04}")).await;
}
for i in (HUB_EDGES + 1)..=(HUB_EDGES + LEAF_EDGES) {
insert_edge(&conn, &format!("c{i:04}"), &format!("c{:04}", i + 1)).await;
}
conn.execute("COMMIT", ()).await.unwrap();
conn
}
async fn insert_edge(conn: &libsql::Connection, source: &str, target: &str) {
conn.execute(
"INSERT INTO links (source_id, target_id, edge_type, valid_from, \
valid_to, weight, properties, recorded_at) \
VALUES (?1, ?2, 'LINKS', ?3, ?4, 1.0, '{}', ?3)",
libsql::params![source, target, TS, OPEN],
)
.await
.unwrap();
}
pub async fn assert_has_statistics(conn: &libsql::Connection) {
let mut rows = conn
.query("SELECT COUNT(*) FROM sqlite_stat1", ())
.await
.expect("sqlite_stat1 missing: ANALYZE did not run on this fixture");
let stats: i64 = rows.next().await.unwrap().unwrap().get(0).unwrap();
assert!(
stats > 0,
"the fixture analysed to zero statistics rows, so this is the \
empty-database case wearing the populated one's name (D-150)"
);
}
pub 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(" | ")
}
#[derive(Debug, PartialEq, Eq)]
pub struct Counts {
pub opens: usize,
pub seeks: usize,
pub rewinds: usize,
}
pub const fn counts(opens: usize, seeks: usize, rewinds: usize) -> Counts {
Counts {
opens,
seeks,
rewinds,
}
}
pub async fn counts_of(conn: &libsql::Connection, sql: &str) -> Counts {
let mut rows = conn.query(&format!("EXPLAIN {sql}"), ()).await.unwrap();
let mut c = counts(0, 0, 0);
while let Some(row) = rows.next().await.unwrap() {
let op: String = row.get(1).unwrap();
if op == "OpenRead" {
c.opens += 1;
} else if op.starts_with("Seek") || op == "NotExists" || op == "NotFound" {
c.seeks += 1;
} else if op == "Rewind" || op == "Last" {
c.rewinds += 1;
}
}
c
}