use cypherlite_core::{DatabaseConfig, LabelRegistry, SyncMode};
use cypherlite_query::api::CypherLite;
use cypherlite_storage::version::VersionRecord;
use tempfile::tempdir;
fn test_db(dir: &std::path::Path) -> CypherLite {
let config = DatabaseConfig {
path: dir.join("test.cyl"),
wal_sync_mode: SyncMode::Normal,
..Default::default()
};
CypherLite::open(config).expect("open")
}
fn test_db_no_versioning(dir: &std::path::Path) -> CypherLite {
let config = DatabaseConfig {
path: dir.join("test.cyl"),
wal_sync_mode: SyncMode::Normal,
version_storage_enabled: false,
..Default::default()
};
CypherLite::open(config).expect("open")
}
#[test]
fn w002_set_creates_version_snapshot() {
let dir = tempdir().expect("tempdir");
let mut db = test_db(dir.path());
db.execute("CREATE (n:Person {name: 'Alice', age: 25})")
.expect("create");
db.execute("MATCH (n:Person) SET n.age = 30").expect("set");
let vs = db.engine().version_store();
assert!(
vs.version_count(1) >= 1,
"expected at least one version snapshot after SET"
);
}
#[test]
fn w002_multiple_sets_create_multiple_snapshots() {
let dir = tempdir().expect("tempdir");
let mut db = test_db(dir.path());
db.execute("CREATE (n:Person {name: 'Alice', age: 25})")
.expect("create");
db.execute("MATCH (n:Person) SET n.age = 30").expect("set1");
db.execute("MATCH (n:Person) SET n.age = 35").expect("set2");
db.execute("MATCH (n:Person) SET n.age = 40").expect("set3");
let vs = db.engine().version_store();
assert_eq!(
vs.version_count(1),
3,
"expected 3 version snapshots after 3 SETs"
);
}
#[test]
fn w003_version_chain_preserves_property_history() {
let dir = tempdir().expect("tempdir");
let mut db = test_db(dir.path());
db.execute("CREATE (n:Person {name: 'Alice', age: 25})")
.expect("create");
db.execute("MATCH (n:Person) SET n.age = 30").expect("set1");
db.execute("MATCH (n:Person) SET n.age = 35").expect("set2");
let vs = db.engine().version_store();
let chain = vs.get_version_chain(1);
assert_eq!(chain.len(), 2);
match &chain[0].1 {
VersionRecord::Node(node) => {
let age_key = db.engine().catalog().prop_key_id("age").expect("age key");
let age_val = node.properties.iter().find(|(k, _)| *k == age_key);
assert!(age_val.is_some(), "first version should have age property");
}
_ => panic!("expected node version"),
}
match &chain[1].1 {
VersionRecord::Node(node) => {
let age_key = db.engine().catalog().prop_key_id("age").expect("age key");
let age_val = node.properties.iter().find(|(k, _)| *k == age_key);
assert!(age_val.is_some(), "second version should have age property");
}
_ => panic!("expected node version"),
}
}
#[test]
fn w003_current_state_is_live_not_versioned() {
let dir = tempdir().expect("tempdir");
let mut db = test_db(dir.path());
db.execute("CREATE (n:Person {name: 'Alice', age: 25})")
.expect("create");
db.execute("MATCH (n:Person) SET n.age = 30").expect("set");
let result = db.execute("MATCH (n:Person) RETURN n.age").expect("match");
assert_eq!(result.rows[0].get_as::<i64>("n.age"), Some(30));
let vs = db.engine().version_store();
let latest = vs.get_latest_version(1).expect("has version");
match latest {
VersionRecord::Node(node) => {
let age_key = db.engine().catalog().prop_key_id("age").expect("age key");
let age_val = node
.properties
.iter()
.find(|(k, _)| *k == age_key)
.map(|(_, v)| v.clone());
assert_eq!(
age_val,
Some(cypherlite_core::PropertyValue::Int64(25)),
"versioned snapshot should have old value"
);
}
_ => panic!("expected node version"),
}
}
#[test]
fn w002_remove_creates_version_snapshot() {
let dir = tempdir().expect("tempdir");
let mut db = test_db(dir.path());
db.execute("CREATE (n:Person {name: 'Alice', age: 25})")
.expect("create");
db.execute("MATCH (n:Person) REMOVE n.age").expect("remove");
let vs = db.engine().version_store();
assert!(
vs.version_count(1) >= 1,
"expected at least one version snapshot after REMOVE"
);
}
#[test]
fn w005_no_snapshots_when_disabled() {
let dir = tempdir().expect("tempdir");
let mut db = test_db_no_versioning(dir.path());
db.execute("CREATE (n:Person {name: 'Alice', age: 25})")
.expect("create");
db.execute("MATCH (n:Person) SET n.age = 30").expect("set");
db.execute("MATCH (n:Person) SET n.age = 35").expect("set2");
let vs = db.engine().version_store();
assert_eq!(
vs.total_versions(),
0,
"no snapshots should be created when version storage is disabled"
);
}
#[test]
fn w001_version_store_accessible() {
let dir = tempdir().expect("tempdir");
let db = test_db(dir.path());
let vs = db.engine().version_store();
assert_eq!(vs.total_versions(), 0);
}