#![cfg(not(target_arch = "wasm32"))]
use minigraf::db::Minigraf;
use minigraf::{QueryResult, Value};
fn open_temp_db() -> (Minigraf, tempfile::TempDir) {
let dir = tempfile::tempdir().unwrap();
let db_path = dir.path().join("test.graph");
let db = Minigraf::open(&db_path).unwrap();
(db, dir)
}
fn count_results(result: QueryResult) -> usize {
match result {
QueryResult::QueryResults { results, .. } => results.len(),
_ => 0,
}
}
fn extract_rows(result: QueryResult) -> Vec<Vec<Value>> {
match result {
QueryResult::QueryResults { results, .. } => results,
other => panic!("expected QueryResults, got {:?}", other),
}
}
#[test]
fn test_query_correct_after_transact_and_reload() {
let dir = tempfile::tempdir().unwrap();
let db_path = dir.path().join("reload.graph");
{
let db = Minigraf::open(&db_path).unwrap();
db.execute(
r#"(transact [[:alice :person/name "Alice"]
[:bob :person/name "Bob"]])"#,
)
.unwrap();
}
{
let db = Minigraf::open(&db_path).unwrap();
let n = count_results(
db.execute(r#"(query [:find ?name :where [?e :person/name ?name]])"#)
.unwrap(),
);
assert_eq!(n, 2, "Both names should be found after reload");
}
}
#[test]
fn test_index_correctness_via_query() {
let (db, _dir) = open_temp_db();
db.execute(r#"(transact [[:a :x 1] [:a :y 2] [:a :link :b]])"#)
.unwrap();
let n = count_results(
db.execute(r#"(query [:find ?v :where [?e :x ?v]])"#)
.unwrap(),
);
assert_eq!(n, 1, "Exactly one entity has attribute :x");
}
#[test]
fn test_bitemporal_valid_at_query_still_correct() {
let (db, _dir) = open_temp_db();
db.execute(
r#"(transact {:valid-from "2023-01-01" :valid-to "2024-01-01"}
[[:alice :status :active]])"#,
)
.unwrap();
db.execute(
r#"(transact {:valid-from "2024-01-01"}
[[:alice :status :retired]])"#,
)
.unwrap();
let rows = extract_rows(
db.execute(r#"(query [:find ?s :valid-at "2023-06-01" :where [:alice :status ?s]])"#)
.unwrap(),
);
assert_eq!(rows.len(), 1, "Should find exactly one status in mid-2023");
assert_eq!(
rows[0][0],
Value::Keyword(":active".to_string()),
"Status in 2023 should be :active"
);
}
#[test]
fn test_as_of_query_still_correct() {
let (db, _dir) = open_temp_db();
db.execute(r#"(transact [[:alice :age 30]])"#).unwrap();
db.execute(r#"(transact [[:alice :age 31]])"#).unwrap();
let rows = extract_rows(
db.execute(r#"(query [:find ?a :as-of 1 :where [:alice :age ?a]])"#)
.unwrap(),
);
assert_eq!(rows.len(), 1, ":as-of 1 should return exactly one age");
assert_eq!(rows[0][0], Value::Integer(30), "Age at tx 1 should be 30");
}
#[test]
fn test_recursive_rules_unchanged_after_6_1() {
let (db, _dir) = open_temp_db();
db.execute(r#"(transact [[:a :connected :b] [:b :connected :c] [:c :connected :d]])"#)
.unwrap();
db.execute(r#"(rule [(reachable ?from ?to) [?from :connected ?to]])"#)
.unwrap();
db.execute(r#"(rule [(reachable ?from ?to) [?from :connected ?mid] (reachable ?mid ?to)])"#)
.unwrap();
let n = count_results(
db.execute(r#"(query [:find ?to :where (reachable :a ?to)])"#)
.unwrap(),
);
assert_eq!(n, 3, ":a can reach :b, :c, :d (3 nodes)");
}
#[test]
fn test_explicit_transaction_with_indexes() {
let (db, _dir) = open_temp_db();
let mut tx = db.begin_write().unwrap();
tx.execute(r#"(transact [[:alice :age 30]])"#).unwrap();
tx.commit().unwrap();
let n = count_results(
db.execute(r#"(query [:find ?a :where [:alice :age ?a]])"#)
.unwrap(),
);
assert_eq!(n, 1, "Committed fact should be visible after explicit tx");
}