pub mod reverse_index;
use cypherlite_core::{GraphEntity, HyperEdgeId, HyperEdgeRecord, PropertyValue};
use std::collections::BTreeMap;
pub struct HyperEdgeStore {
records: BTreeMap<u64, HyperEdgeRecord>,
next_id: u64,
}
impl HyperEdgeStore {
pub fn new(start_id: u64) -> Self {
Self {
records: BTreeMap::new(),
next_id: start_id,
}
}
pub fn create(
&mut self,
rel_type_id: u32,
sources: Vec<GraphEntity>,
targets: Vec<GraphEntity>,
properties: Vec<(u32, PropertyValue)>,
) -> HyperEdgeId {
let id = HyperEdgeId(self.next_id);
let record = HyperEdgeRecord {
id,
rel_type_id,
sources,
targets,
properties,
};
self.records.insert(self.next_id, record);
self.next_id += 1;
id
}
pub fn get(&self, id: HyperEdgeId) -> Option<&HyperEdgeRecord> {
self.records.get(&id.0)
}
pub fn delete(&mut self, id: HyperEdgeId) -> Option<HyperEdgeRecord> {
self.records.remove(&id.0)
}
pub fn next_id(&self) -> u64 {
self.next_id
}
pub fn len(&self) -> usize {
self.records.len()
}
pub fn is_empty(&self) -> bool {
self.records.is_empty()
}
pub fn all(&self) -> impl Iterator<Item = &HyperEdgeRecord> {
self.records.values()
}
pub fn insert_loaded_record(&mut self, record: HyperEdgeRecord) {
let id = record.id.0;
self.records.insert(id, record);
if id >= self.next_id {
self.next_id = id + 1;
}
}
}
impl Default for HyperEdgeStore {
fn default() -> Self {
Self::new(1)
}
}
#[cfg(test)]
mod tests {
use cypherlite_core::{GraphEntity, HyperEdgeId, NodeId, PropertyValue};
use super::*;
#[test]
fn test_hyperedge_store_new_is_empty() {
let store = HyperEdgeStore::new(1);
assert_eq!(store.len(), 0);
assert!(store.is_empty());
}
#[test]
fn test_create_hyperedge() {
let mut store = HyperEdgeStore::new(1);
let id = store.create(
1,
vec![GraphEntity::Node(NodeId(10))],
vec![GraphEntity::Node(NodeId(20))],
vec![],
);
assert_eq!(id, HyperEdgeId(1));
assert_eq!(store.len(), 1);
assert!(!store.is_empty());
}
#[test]
fn test_create_multiple_hyperedges() {
let mut store = HyperEdgeStore::new(1);
let id1 = store.create(1, vec![], vec![], vec![]);
let id2 = store.create(2, vec![], vec![], vec![]);
let id3 = store.create(3, vec![], vec![], vec![]);
assert_eq!(id1, HyperEdgeId(1));
assert_eq!(id2, HyperEdgeId(2));
assert_eq!(id3, HyperEdgeId(3));
assert_eq!(store.len(), 3);
}
#[test]
fn test_get_hyperedge() {
let mut store = HyperEdgeStore::new(1);
let id = store.create(
5,
vec![GraphEntity::Node(NodeId(1))],
vec![GraphEntity::Node(NodeId(2))],
vec![(1, PropertyValue::Int64(42))],
);
let record = store.get(id).expect("found");
assert_eq!(record.id, id);
assert_eq!(record.rel_type_id, 5);
assert_eq!(record.sources.len(), 1);
assert_eq!(record.targets.len(), 1);
assert_eq!(record.properties.len(), 1);
}
#[test]
fn test_get_nonexistent_hyperedge() {
let store = HyperEdgeStore::new(1);
assert!(store.get(HyperEdgeId(999)).is_none());
}
#[test]
fn test_delete_hyperedge() {
let mut store = HyperEdgeStore::new(1);
let id = store.create(1, vec![], vec![], vec![]);
let deleted = store.delete(id);
assert!(deleted.is_some());
assert!(store.get(id).is_none());
assert_eq!(store.len(), 0);
}
#[test]
fn test_delete_nonexistent_hyperedge() {
let mut store = HyperEdgeStore::new(1);
assert!(store.delete(HyperEdgeId(999)).is_none());
}
#[test]
fn test_all_iterator() {
let mut store = HyperEdgeStore::new(1);
store.create(1, vec![], vec![], vec![]);
store.create(2, vec![], vec![], vec![]);
let all: Vec<_> = store.all().collect();
assert_eq!(all.len(), 2);
}
#[test]
fn test_next_id() {
let mut store = HyperEdgeStore::new(1);
assert_eq!(store.next_id(), 1);
store.create(1, vec![], vec![], vec![]);
assert_eq!(store.next_id(), 2);
}
#[test]
fn test_hyperedge_store_default() {
let store = HyperEdgeStore::default();
assert_eq!(store.len(), 0);
assert_eq!(store.next_id(), 1);
}
}