use libsql::{Builder, OpenFlags};
use macrame::prelude::*;
async fn report<E: std::fmt::Display>(label: &str, r: std::result::Result<(), E>) {
match r {
Ok(()) => println!(" {label:<44} ALLOWED"),
Err(e) => println!(" {label:<44} refused: {e}"),
}
}
#[tokio::main]
async fn main() {
let dir = tempfile::TempDir::new().unwrap();
let path = dir.path().join("probe.db");
let db = Database::open_with_cadence(&path, None).await.unwrap();
db.write_concepts(vec![ConceptUpsert::new("a", "A")
.content("body")
.valid_from("2026-01-01T00:00:00.000000Z")])
.await
.unwrap();
println!("journal mode: {}", {
let mut rows = db
.read_conn()
.query("PRAGMA journal_mode", ())
.await
.unwrap();
rows.next()
.await
.unwrap()
.unwrap()
.get::<String>(0)
.unwrap()
});
let ro = Builder::new_local(&path)
.flags(OpenFlags::SQLITE_OPEN_READ_ONLY)
.build()
.await;
let ro = match ro {
Ok(d) => {
println!("\nread-only open: OK");
d
}
Err(e) => {
println!("\nread-only open FAILED: {e}");
return;
}
};
let conn = ro.connect().unwrap();
println!("\nthrough a SQLITE_OPEN_READ_ONLY connection:");
let read = conn
.query("SELECT COUNT(*) FROM concepts", ())
.await
.map(|_| ());
report("SELECT COUNT(*) FROM concepts", read).await;
let explain = conn
.query("EXPLAIN QUERY PLAN SELECT * FROM links_current", ())
.await
.map(|_| ());
report("EXPLAIN QUERY PLAN", explain).await;
let ins = conn
.execute(
"INSERT INTO concepts (id, title, content, valid_from, valid_to, \
recorded_at, retired) VALUES ('x','X','','2026-01-01T00:00:00.000000Z', \
'9999-12-31T23:59:59.999999Z','2026-01-01T00:00:00.000000Z',0)",
(),
)
.await
.map(|_| ());
report("INSERT", ins).await;
let ddl = conn
.execute("CREATE TABLE t (x INTEGER)", ())
.await
.map(|_| ());
report("CREATE TABLE", ddl).await;
let tmp = conn
.execute("CREATE TEMP TABLE t (x INTEGER)", ())
.await
.map(|_| ());
report("CREATE TEMP TABLE", tmp).await;
let off = conn
.execute("PRAGMA query_only = OFF", ())
.await
.map(|_| ());
report("PRAGMA query_only = OFF", off).await;
let ins2 = conn
.execute(
"INSERT INTO concepts (id, title, content, valid_from, valid_to, \
recorded_at, retired) VALUES ('y','Y','','2026-01-01T00:00:00.000000Z', \
'9999-12-31T23:59:59.999999Z','2026-01-01T00:00:00.000000Z',0)",
(),
)
.await
.map(|_| ());
report("INSERT after query_only = OFF", ins2).await;
println!("\nthrough read_conn() (PRAGMA query_only = ON), for comparison:");
let rc = db.read_conn();
let ins3 = rc
.execute(
"INSERT INTO concepts (id, title, content, valid_from, valid_to, \
recorded_at, retired) VALUES ('z','Z','','2026-01-01T00:00:00.000000Z', \
'9999-12-31T23:59:59.999999Z','2026-01-01T00:00:00.000000Z',0)",
(),
)
.await
.map(|_| ());
report("INSERT", ins3).await;
let off2 = rc.execute("PRAGMA query_only = OFF", ()).await.map(|_| ());
report("PRAGMA query_only = OFF", off2).await;
let ins4 = rc
.execute(
"INSERT INTO concepts (id, title, content, valid_from, valid_to, \
recorded_at, retired) VALUES ('w','W','','2026-01-01T00:00:00.000000Z', \
'9999-12-31T23:59:59.999999Z','2026-01-01T00:00:00.000000Z',0)",
(),
)
.await
.map(|_| ());
report("INSERT after query_only = OFF", ins4).await;
let _ = rc.execute("PRAGMA query_only = ON", ()).await;
let missing = dir.path().join("nope.db");
let r = Builder::new_local(&missing)
.flags(OpenFlags::SQLITE_OPEN_READ_ONLY)
.build()
.await;
println!(
"\nread-only open of a nonexistent path: {}",
match r {
Ok(d) => match d.connect() {
Ok(_) => "build OK, connect OK (file created?)".to_string(),
Err(e) => format!("build OK, connect failed: {e}"),
},
Err(e) => format!("failed: {e}"),
}
);
println!(" file now exists: {}", missing.exists());
drop(conn);
drop(ro);
db.close().await.unwrap();
}