pub mod read_tx;
pub mod types;
pub mod visibility;
pub mod write;
pub mod write_buffer;
pub use read_tx::ReadTransaction;
pub use types::{TxId, TxMetadata, TxState};
pub use visibility::{TransactionSnapshot, TxVisibilityManager};
pub use write::WriteTransaction;
pub use write_buffer::{BufferedWrite, WriteBuffer};
use crate::core::error::Result;
use crate::core::graph::{Edge, Node};
#[cfg(test)]
use crate::core::id::MAX_VALID_ID;
use crate::core::id::{EdgeId, NodeId};
use crate::core::property::{PropertyMap, PropertyValue};
use crate::core::temporal::Timestamp;
pub trait ReadOps {
fn get_node(&self, id: NodeId) -> Result<Node>;
fn get_edge(&self, id: EdgeId) -> Result<Edge>;
fn get_outgoing_edges(&self, node_id: NodeId) -> Vec<EdgeId>;
fn get_incoming_edges(&self, node_id: NodeId) -> Vec<EdgeId>;
fn get_outgoing_edges_with_label(&self, node_id: NodeId, label: &str) -> Vec<EdgeId>;
fn node_count(&self) -> usize;
fn edge_count(&self) -> usize;
fn find_nodes_by_property(
&self,
label: &str,
property_key: &str,
property_value: &PropertyValue,
) -> Vec<NodeId>;
}
pub trait WriteOps: ReadOps {
fn create_node_with_valid_time(
&mut self,
label: &str,
properties: PropertyMap,
valid_from: Option<Timestamp>,
) -> Result<NodeId>;
fn create_node(&mut self, label: &str, properties: PropertyMap) -> Result<NodeId> {
self.create_node_with_valid_time(label, properties, None)
}
fn create_edge_with_valid_time(
&mut self,
source: NodeId,
target: NodeId,
label: &str,
properties: PropertyMap,
valid_from: Option<Timestamp>,
) -> Result<EdgeId>;
fn create_edge(
&mut self,
source: NodeId,
target: NodeId,
label: &str,
properties: PropertyMap,
) -> Result<EdgeId> {
self.create_edge_with_valid_time(source, target, label, properties, None)
}
fn update_node_with_valid_time(
&mut self,
node_id: NodeId,
properties: PropertyMap,
valid_from: Option<Timestamp>,
) -> Result<()>;
fn update_node(&mut self, node_id: NodeId, properties: PropertyMap) -> Result<()> {
self.update_node_with_valid_time(node_id, properties, None)
}
fn update_edge_with_valid_time(
&mut self,
edge_id: EdgeId,
properties: PropertyMap,
valid_from: Option<Timestamp>,
) -> Result<()>;
fn update_edge(&mut self, edge_id: EdgeId, properties: PropertyMap) -> Result<()> {
self.update_edge_with_valid_time(edge_id, properties, None)
}
fn delete_node_with_valid_time(
&mut self,
node_id: NodeId,
valid_from: Option<Timestamp>,
) -> Result<()>;
fn delete_node(&mut self, node_id: NodeId) -> Result<()> {
self.delete_node_with_valid_time(node_id, None)
}
fn delete_node_cascade(&mut self, node_id: NodeId) -> Result<()>;
fn delete_edge_with_valid_time(
&mut self,
edge_id: EdgeId,
valid_from: Option<Timestamp>,
) -> Result<()>;
fn delete_edge(&mut self, edge_id: EdgeId) -> Result<()> {
self.delete_edge_with_valid_time(edge_id, None)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::AletheiaDB;
use crate::core::property::PropertyMapBuilder;
use crate::core::temporal::time;
#[test]
fn test_create_node_with_valid_time_trait_method_exists() {
fn assert_write_ops<T: WriteOps>(_tx: &mut T) {
}
let db = AletheiaDB::new().unwrap();
let mut tx = db.write_transaction().unwrap();
assert_write_ops(&mut tx);
}
#[test]
fn test_create_node_default_delegates_to_with_valid_time() {
let db = AletheiaDB::new().unwrap();
let mut tx = db.write_transaction().unwrap();
let props1 = PropertyMapBuilder::new().insert("name", "Test1").build();
let props2 = PropertyMapBuilder::new().insert("name", "Test2").build();
let result1 = tx.create_node("Test", props1);
assert!(result1.is_ok(), "create_node failed: {:?}", result1.err());
let id1 = result1.unwrap();
let result2 = tx.create_node_with_valid_time("Test", props2, None);
assert!(
result2.is_ok(),
"create_node_with_valid_time failed: {:?}",
result2.err()
);
let id2 = result2.unwrap();
assert_ne!(id1, id2, "IDs should be unique");
assert!(id1.as_u64() < id2.as_u64(), "IDs should increment");
}
#[test]
fn test_create_node_with_backdated_valid_time() {
let db = AletheiaDB::new().unwrap();
let mut tx = db.write_transaction().unwrap();
let one_hour_ago = time::now().wallclock() - 3_600_000_000;
let valid_from = crate::core::hlc::HybridTimestamp::new(one_hour_ago, 0).unwrap();
let props = PropertyMapBuilder::new().insert("name", "Alice").build();
let node_id = tx
.create_node_with_valid_time("Person", props, Some(valid_from))
.unwrap();
assert!(node_id.as_u64() <= MAX_VALID_ID);
}
#[test]
fn test_create_edge_with_valid_time_trait_method_exists() {
fn assert_write_ops<T: WriteOps>(_tx: &mut T) {
}
let db = AletheiaDB::new().unwrap();
let mut tx = db.write_transaction().unwrap();
assert_write_ops(&mut tx);
}
#[test]
fn test_update_node_with_valid_time_trait_method_exists() {
fn assert_write_ops<T: WriteOps>(_tx: &mut T) {
}
let db = AletheiaDB::new().unwrap();
let mut tx = db.write_transaction().unwrap();
assert_write_ops(&mut tx);
}
#[test]
fn test_delete_node_with_valid_time_trait_method_exists() {
fn assert_write_ops<T: WriteOps>(_tx: &mut T) {
}
let db = AletheiaDB::new().unwrap();
let mut tx = db.write_transaction().unwrap();
assert_write_ops(&mut tx);
}
}