#![cfg(feature = "hypergraph")]
use cypherlite_core::{DatabaseConfig, SyncMode};
use cypherlite_query::api::CypherLite;
use tempfile::tempdir;
fn test_config(dir: &std::path::Path) -> DatabaseConfig {
DatabaseConfig {
path: dir.join("test.cyl"),
wal_sync_mode: SyncMode::Normal,
..Default::default()
}
}
#[test]
fn test_create_hyperedge_single_source() {
let dir = tempdir().expect("tempdir");
let mut db = CypherLite::open(test_config(dir.path())).expect("open");
db.execute("CREATE (a:HESrc {name: 'Alice'})")
.expect("create");
db.execute("MATCH (a:HESrc) CREATE HYPEREDGE (h:Solo) FROM (a) TO ()")
.expect("create hyperedge");
let result = db.execute("MATCH HYPEREDGE (h) RETURN h").expect("match");
assert_eq!(result.rows.len(), 1, "should find one hyperedge");
}
#[test]
fn test_match_hyperedge_scan_multiple() {
let dir = tempdir().expect("tempdir");
let mut db = CypherLite::open(test_config(dir.path())).expect("open");
db.execute("CREATE (a:ScanX {name: 'A'})").expect("a");
db.execute("CREATE (b:ScanY {name: 'B'})").expect("b");
db.execute("MATCH (a:ScanX) CREATE HYPEREDGE (h1:TypeA) FROM (a) TO ()")
.expect("he1");
db.execute("MATCH (b:ScanY) CREATE HYPEREDGE (h2:TypeB) FROM (b) TO ()")
.expect("he2");
let result = db.execute("MATCH HYPEREDGE (h) RETURN h").expect("match");
assert_eq!(result.rows.len(), 2, "should find 2 hyperedges");
}
#[test]
fn test_create_hyperedge_empty_participants() {
let dir = tempdir().expect("tempdir");
let mut db = CypherLite::open(test_config(dir.path())).expect("open");
db.execute("CREATE HYPEREDGE (h:Empty) FROM () TO ()")
.expect("empty hyperedge");
let result = db.execute("MATCH HYPEREDGE (h) RETURN h").expect("match");
assert_eq!(result.rows.len(), 1, "should create one empty hyperedge");
}
#[test]
fn test_multiple_hyperedge_types() {
let dir = tempdir().expect("tempdir");
let mut db = CypherLite::open(test_config(dir.path())).expect("open");
db.execute("CREATE (a:MultiSrc {name: 'A'})").expect("a");
db.execute("MATCH (a:MultiSrc) CREATE HYPEREDGE (h1:Meeting) FROM (a) TO ()")
.expect("meeting");
db.execute("MATCH (a:MultiSrc) CREATE HYPEREDGE (h2:Call) FROM (a) TO ()")
.expect("call");
db.execute("MATCH (a:MultiSrc) CREATE HYPEREDGE (h3:Email) FROM (a) TO ()")
.expect("email");
let result = db.execute("MATCH HYPEREDGE (h) RETURN h").expect("all");
assert_eq!(result.rows.len(), 3, "should have 3 hyperedges total");
}
#[test]
fn test_hyperedge_two_participants_via_chain() {
let dir = tempdir().expect("tempdir");
let mut db = CypherLite::open(test_config(dir.path())).expect("open");
db.execute("CREATE (a:TwoA {name: 'start'})-[:NEXT]->(b:TwoB {name: 'end'})")
.expect("chain");
db.execute("MATCH (a:TwoA)-[:NEXT]->(b:TwoB) CREATE HYPEREDGE (h:Step) FROM (a) TO (b)")
.expect("step hyperedge");
let result = db.execute("MATCH HYPEREDGE (h) RETURN h").expect("match");
assert_eq!(result.rows.len(), 1, "should have 1 hyperedge");
}
#[test]
fn test_temporal_ref_hyperedge_creation() {
let dir = tempdir().expect("tempdir");
let mut db = CypherLite::open(test_config(dir.path())).expect("open");
db.execute("CREATE (a:TempSrc {name: 'Alice'})-[:KNOWS]->(b:TempTgt {name: 'target'})")
.expect("create chain");
db.execute(
"MATCH (a:TempSrc)-[:KNOWS]->(b:TempTgt) CREATE HYPEREDGE (h:Snap) FROM (a AT TIME 100) TO (b)",
)
.expect("temporal hyperedge");
let result = db.execute("MATCH HYPEREDGE (h) RETURN h").expect("match");
assert_eq!(result.rows.len(), 1, "temporal hyperedge should exist");
}
#[test]
fn test_create_hyperedge_standalone() {
let dir = tempdir().expect("tempdir");
let mut db = CypherLite::open(test_config(dir.path())).expect("open");
db.execute("CREATE HYPEREDGE (h:Standalone) FROM () TO ()")
.expect("standalone");
let result = db.execute("MATCH HYPEREDGE (h) RETURN h").expect("match");
assert_eq!(result.rows.len(), 1);
}