#![cfg(feature = "std")]
use graphitesql::btree::{create_table_root, insert_table};
use graphitesql::format::encode_record;
use graphitesql::pager::WritePager;
use graphitesql::vfs::{std_file::StdVfs, OpenFlags, Vfs};
use graphitesql::{Connection, Value};
use std::process::Command;
fn temp_path(name: &str) -> String {
let mut p = std::env::temp_dir();
p.push(format!("graphitesql-wc-{}-{name}", std::process::id()));
p.to_string_lossy().into_owned()
}
fn build_db(path: &str, n: i64) {
let vfs = StdVfs::new();
let _ = vfs.delete(path);
let _ = vfs.delete(&format!("{path}-journal"));
let file = vfs.open(path, OpenFlags::READ_WRITE_CREATE).unwrap();
let journal = vfs
.open(&format!("{path}-journal"), OpenFlags::READ_WRITE_CREATE)
.unwrap();
let mut wp = WritePager::create(file, Some(journal), 4096).unwrap();
let root = create_table_root(&mut wp).unwrap();
let schema_row = encode_record(&[
Value::Text("table".into()),
Value::Text("t".into()),
Value::Text("t".into()),
Value::Integer(root as i64),
Value::Text("CREATE TABLE t(a INTEGER PRIMARY KEY, b TEXT, c REAL)".into()),
]);
insert_table(&mut wp, 1, 1, &schema_row).unwrap();
for i in 1..=n {
let row = encode_record(&[
Value::Null,
Value::Text(format!("row-{i}")),
Value::Real(i as f64 + 0.5),
]);
insert_table(&mut wp, root, i, &row).unwrap();
}
wp.commit().unwrap();
}
#[test]
fn graphitesql_reads_back_its_own_writes() {
let path = temp_path("roundtrip.db");
build_db(&path, 50);
let c = Connection::open_readonly(&path).unwrap();
let r = c.query("SELECT a, b, c FROM t ORDER BY a").unwrap();
assert_eq!(r.rows.len(), 50);
assert_eq!(r.rows[0][0], Value::Integer(1));
assert_eq!(r.rows[0][1], Value::Text("row-1".into()));
assert_eq!(r.rows[49][0], Value::Integer(50));
let agg = c.query("SELECT count(*), sum(a) FROM t").unwrap();
assert_eq!(agg.rows[0][0], Value::Integer(50));
assert_eq!(agg.rows[0][1], Value::Integer(50 * 51 / 2));
let _ = StdVfs::new().delete(&path);
}
#[test]
fn many_rows_with_splits_read_back() {
let path = temp_path("splits.db");
build_db(&path, 1500); let c = Connection::open_readonly(&path).unwrap();
let r = c.query("SELECT count(*), min(a), max(a) FROM t").unwrap();
assert_eq!(
r.rows[0],
vec![
Value::Integer(1500),
Value::Integer(1),
Value::Integer(1500)
]
);
let _ = StdVfs::new().delete(&path);
}
#[test]
fn sqlite3_cli_opens_graphitesql_database() {
if Command::new("sqlite3").arg("--version").output().is_err() {
eprintln!("sqlite3 CLI not found; skipping cross-engine compatibility check");
return;
}
let path = temp_path("forsqlite.db");
build_db(&path, 200);
let run = |sql: &str| -> String {
let out = Command::new("sqlite3")
.arg(&path)
.arg(sql)
.output()
.expect("run sqlite3");
assert!(
out.status.success(),
"sqlite3 failed: {}",
String::from_utf8_lossy(&out.stderr)
);
String::from_utf8_lossy(&out.stdout).trim().to_string()
};
assert_eq!(run("PRAGMA integrity_check;"), "ok");
assert_eq!(run("SELECT count(*) FROM t;"), "200");
assert_eq!(run("SELECT b FROM t WHERE a = 1;"), "row-1");
assert_eq!(run("SELECT a FROM t ORDER BY a DESC LIMIT 1;"), "200");
assert_eq!(run("SELECT c FROM t WHERE a = 2;"), "2.5");
let _ = StdVfs::new().delete(&path);
}