diff --git a/helixdb/src/helix_engine/graph_core/mod.rs b/helixdb/src/helix_engine/graph_core/mod.rs index a91f8170..20eeffdb 100644 --- a/helixdb/src/helix_engine/graph_core/mod.rs +++ b/helixdb/src/helix_engine/graph_core/mod.rs @@ -2,6 +2,5 @@ pub mod config; pub mod graph_core; pub mod ops; pub mod traversal_iter; - #[cfg(test)] mod traversal_tests; diff --git a/helixdb/src/helix_engine/graph_core/ops/g.rs b/helixdb/src/helix_engine/graph_core/ops/g.rs index dd722305..462ca682 100644 --- a/helixdb/src/helix_engine/graph_core/ops/g.rs +++ b/helixdb/src/helix_engine/graph_core/ops/g.rs @@ -4,7 +4,7 @@ use crate::helix_engine::{ storage_core::storage_core::HelixGraphStorage, types::GraphError, }; -use heed3::{RoTxn, RwTxn}; +use heed3::{RoTxn, RwTxn, WithoutTls}; use std::sync::Arc; pub struct G {} @@ -27,7 +27,7 @@ impl G { #[inline] pub fn new<'a>( storage: Arc, - txn: &'a RoTxn<'a>, + txn: &'a RoTxn<'a, WithoutTls>, ) -> RoTraversalIterator<'a, impl Iterator>> where Self: Sized, @@ -56,7 +56,7 @@ impl G { /// ``` pub fn new_from<'a>( storage: Arc, - txn: &'a RoTxn<'a>, + txn: &'a RoTxn<'a, WithoutTls>, items: Vec, ) -> RoTraversalIterator<'a, impl Iterator>> { RoTraversalIterator { diff --git a/helixdb/src/helix_engine/graph_core/ops/in_/in_.rs b/helixdb/src/helix_engine/graph_core/ops/in_/in_.rs index 64ad075d..73d36d4e 100644 --- a/helixdb/src/helix_engine/graph_core/ops/in_/in_.rs +++ b/helixdb/src/helix_engine/graph_core/ops/in_/in_.rs @@ -12,7 +12,7 @@ use crate::{ }, protocol::label_hash::hash_label, }; -use heed3::{types::Bytes, RoTxn}; +use heed3::{types::Bytes, RoTxn, WithoutTls}; use std::sync::Arc; pub struct InNodesIterator<'a, T> { @@ -27,7 +27,7 @@ pub struct InNodesIterator<'a, T> { edge_type: &'a EdgeType, } -impl<'a> Iterator for InNodesIterator<'a, RoTxn<'a>> { +impl<'a> Iterator for InNodesIterator<'a, RoTxn<'a, WithoutTls>> { type Item = Result; fn next(&mut self) -> Option { @@ -78,7 +78,7 @@ pub trait InAdapter<'a, T>: Iterator> { ) -> RoTraversalIterator<'a, impl Iterator>>; } -impl<'a, I: Iterator> + 'a> InAdapter<'a, RoTxn<'a>> +impl<'a, I: Iterator> + 'a> InAdapter<'a, RoTxn<'a, WithoutTls>> for RoTraversalIterator<'a, I> { #[inline] diff --git a/helixdb/src/helix_engine/graph_core/ops/in_/in_e.rs b/helixdb/src/helix_engine/graph_core/ops/in_/in_e.rs index 16bb28ff..d15c1c7d 100644 --- a/helixdb/src/helix_engine/graph_core/ops/in_/in_e.rs +++ b/helixdb/src/helix_engine/graph_core/ops/in_/in_e.rs @@ -9,7 +9,7 @@ use crate::{ }, protocol::label_hash::hash_label, }; -use heed3::{types::Bytes, RoTxn}; +use heed3::{types::Bytes, RoTxn, WithoutTls}; use std::sync::Arc; pub struct InEdgesIterator<'a, T> { @@ -23,7 +23,7 @@ pub struct InEdgesIterator<'a, T> { txn: &'a T, } -impl<'a> Iterator for InEdgesIterator<'a, RoTxn<'a>> { +impl<'a> Iterator for InEdgesIterator<'a, RoTxn<'a, WithoutTls>> { type Item = Result; fn next(&mut self) -> Option { @@ -64,7 +64,7 @@ pub trait InEdgesAdapter<'a, T>: Iterator RoTraversalIterator<'a, impl Iterator>>; } -impl<'a, I: Iterator>> InEdgesAdapter<'a, RoTxn<'a>> +impl<'a, I: Iterator>> InEdgesAdapter<'a, RoTxn<'a, WithoutTls>> for RoTraversalIterator<'a, I> { #[inline] diff --git a/helixdb/src/helix_engine/graph_core/ops/in_/to_n.rs b/helixdb/src/helix_engine/graph_core/ops/in_/to_n.rs index 3e590700..2a49b165 100644 --- a/helixdb/src/helix_engine/graph_core/ops/in_/to_n.rs +++ b/helixdb/src/helix_engine/graph_core/ops/in_/to_n.rs @@ -3,7 +3,7 @@ use crate::helix_engine::{ storage_core::{storage_core::HelixGraphStorage, storage_methods::StorageMethods}, types::GraphError, }; -use heed3::RoTxn; +use heed3::{RoTxn, WithoutTls}; use std::sync::Arc; pub struct ToNIterator<'a, I, T> { @@ -13,7 +13,7 @@ pub struct ToNIterator<'a, I, T> { } // implementing iterator for OutIterator -impl<'a, I> Iterator for ToNIterator<'a, I, RoTxn<'a>> +impl<'a, I> Iterator for ToNIterator<'a, I, RoTxn<'a, WithoutTls>> where I: Iterator>, { @@ -43,7 +43,7 @@ pub trait ToNAdapter<'a, T>: Iterator> { ) -> RoTraversalIterator<'a, impl Iterator>>; } -impl<'a, I: Iterator>> ToNAdapter<'a, RoTxn<'a>> +impl<'a, I: Iterator>> ToNAdapter<'a, RoTxn<'a, WithoutTls>> for RoTraversalIterator<'a, I> { #[inline(always)] diff --git a/helixdb/src/helix_engine/graph_core/ops/out/from_n.rs b/helixdb/src/helix_engine/graph_core/ops/out/from_n.rs index a5dd8e2d..2d11484e 100644 --- a/helixdb/src/helix_engine/graph_core/ops/out/from_n.rs +++ b/helixdb/src/helix_engine/graph_core/ops/out/from_n.rs @@ -3,7 +3,7 @@ use crate::helix_engine::{ storage_core::{storage_core::HelixGraphStorage, storage_methods::StorageMethods}, types::GraphError, }; -use heed3::RoTxn; +use heed3::{RoTxn, WithoutTls}; use std::sync::Arc; pub struct FromNIterator<'a, I, T> { @@ -12,7 +12,7 @@ pub struct FromNIterator<'a, I, T> { txn: &'a T, } -impl<'a, I> Iterator for FromNIterator<'a, I, RoTxn<'a>> +impl<'a, I> Iterator for FromNIterator<'a, I, RoTxn<'a, WithoutTls>> where I: Iterator>, { @@ -44,7 +44,7 @@ pub trait FromNAdapter<'a, T>: Iterator> ) -> RoTraversalIterator<'a, impl Iterator>>; } -impl<'a, I: Iterator> + 'a> FromNAdapter<'a, RoTxn<'a>> +impl<'a, I: Iterator> + 'a> FromNAdapter<'a, RoTxn<'a, WithoutTls>> for RoTraversalIterator<'a, I> { #[inline(always)] diff --git a/helixdb/src/helix_engine/graph_core/ops/out/out.rs b/helixdb/src/helix_engine/graph_core/ops/out/out.rs index efe83f49..fde1fad3 100644 --- a/helixdb/src/helix_engine/graph_core/ops/out/out.rs +++ b/helixdb/src/helix_engine/graph_core/ops/out/out.rs @@ -12,7 +12,7 @@ use crate::{ }, protocol::label_hash::hash_label, }; -use heed3::{types::Bytes, RoTxn}; +use heed3::{types::Bytes, RoTxn, WithoutTls}; use std::sync::Arc; pub struct OutNodesIterator<'a, T> { @@ -27,7 +27,7 @@ pub struct OutNodesIterator<'a, T> { txn: &'a T, } -impl<'a> Iterator for OutNodesIterator<'a, RoTxn<'a>> { +impl<'a> Iterator for OutNodesIterator<'a, RoTxn<'a, WithoutTls>> { type Item = Result; fn next(&mut self) -> Option { @@ -78,7 +78,7 @@ pub trait OutAdapter<'a, T>: Iterator> { ) -> RoTraversalIterator<'a, impl Iterator>>; } -impl<'a, I: Iterator>> OutAdapter<'a, RoTxn<'a>> +impl<'a, I: Iterator>> OutAdapter<'a, RoTxn<'a, WithoutTls>> for RoTraversalIterator<'a, I> { #[inline] diff --git a/helixdb/src/helix_engine/graph_core/ops/out/out_e.rs b/helixdb/src/helix_engine/graph_core/ops/out/out_e.rs index cfaf1cb7..2dc4f2ef 100644 --- a/helixdb/src/helix_engine/graph_core/ops/out/out_e.rs +++ b/helixdb/src/helix_engine/graph_core/ops/out/out_e.rs @@ -9,7 +9,7 @@ use crate::{ }, protocol::label_hash::hash_label, }; -use heed3::{types::Bytes, RoTxn}; +use heed3::{types::Bytes, RoTxn, WithoutTls}; use std::sync::Arc; pub struct OutEdgesIterator<'a, T> { @@ -23,7 +23,7 @@ pub struct OutEdgesIterator<'a, T> { txn: &'a T, } -impl<'a> Iterator for OutEdgesIterator<'a, RoTxn<'a>> { +impl<'a> Iterator for OutEdgesIterator<'a, RoTxn<'a, WithoutTls>> { type Item = Result; fn next(&mut self) -> Option { @@ -64,7 +64,7 @@ pub trait OutEdgesAdapter<'a, T>: Iterator RoTraversalIterator<'a, impl Iterator>>; } -impl<'a, I: Iterator> + 'a> OutEdgesAdapter<'a, RoTxn<'a>> +impl<'a, I: Iterator> + 'a> OutEdgesAdapter<'a, RoTxn<'a, WithoutTls>> for RoTraversalIterator<'a, I> { #[inline] diff --git a/helixdb/src/helix_engine/graph_core/ops/source/e_from_id.rs b/helixdb/src/helix_engine/graph_core/ops/source/e_from_id.rs index c80b63d5..a8d151e1 100644 --- a/helixdb/src/helix_engine/graph_core/ops/source/e_from_id.rs +++ b/helixdb/src/helix_engine/graph_core/ops/source/e_from_id.rs @@ -6,7 +6,7 @@ use crate::{ }, protocol::items::Edge, }; -use heed3::RoTxn; +use heed3::{RoTxn, WithoutTls}; use std::{iter::Once, sync::Arc}; pub struct EFromId<'a, T> { @@ -16,7 +16,7 @@ pub struct EFromId<'a, T> { id: &'a u128, } -impl<'a> Iterator for EFromId<'a, RoTxn<'a>> { +impl<'a> Iterator for EFromId<'a, RoTxn<'a, WithoutTls>> { type Item = Result; @@ -42,7 +42,7 @@ pub trait EFromIdAdapter<'a>: Iterator> impl<'a, I: Iterator>> EFromIdAdapter<'a> for RoTraversalIterator<'a, I> { - type OutputIter = RoTraversalIterator<'a, EFromId<'a, RoTxn<'a>>>; + type OutputIter = RoTraversalIterator<'a, EFromId<'a, RoTxn<'a, WithoutTls>>>; #[inline] fn e_from_id(self, id: &'a u128) -> Self::OutputIter { diff --git a/helixdb/src/helix_engine/graph_core/ops/source/n_from_id.rs b/helixdb/src/helix_engine/graph_core/ops/source/n_from_id.rs index 66580018..35474de2 100644 --- a/helixdb/src/helix_engine/graph_core/ops/source/n_from_id.rs +++ b/helixdb/src/helix_engine/graph_core/ops/source/n_from_id.rs @@ -6,7 +6,7 @@ use crate::{ }, protocol::items::Node, }; -use heed3::RoTxn; +use heed3::{RoTxn, WithoutTls}; use std::{iter::Once, sync::Arc}; pub struct NFromId<'a, T> { @@ -16,7 +16,7 @@ pub struct NFromId<'a, T> { id: u128, } -impl<'a> Iterator for NFromId<'a, RoTxn<'a>> { +impl<'a> Iterator for NFromId<'a, RoTxn<'a, WithoutTls>> { type Item = Result; fn next(&mut self) -> Option { @@ -42,7 +42,7 @@ pub trait NFromIdAdapter<'a>: Iterator> impl<'a, I: Iterator>> NFromIdAdapter<'a> for RoTraversalIterator<'a, I> { - type OutputIter = RoTraversalIterator<'a, NFromId<'a, RoTxn<'a>>>; + type OutputIter = RoTraversalIterator<'a, NFromId<'a, RoTxn<'a, WithoutTls>>>; #[inline] fn n_from_id(self, id: &u128) -> Self::OutputIter { diff --git a/helixdb/src/helix_engine/graph_core/ops/source/n_from_index.rs b/helixdb/src/helix_engine/graph_core/ops/source/n_from_index.rs index b51f2e0b..b0861885 100644 --- a/helixdb/src/helix_engine/graph_core/ops/source/n_from_index.rs +++ b/helixdb/src/helix_engine/graph_core/ops/source/n_from_index.rs @@ -6,7 +6,7 @@ use crate::{ }, protocol::value::Value, }; -use heed3::RoTxn; +use heed3::{RoTxn, WithoutTls}; use serde::Serialize; use std::{iter::Once, sync::Arc}; @@ -18,7 +18,7 @@ pub struct NFromIndex<'a, T, K: Into + Serialize> { key: &'a K, } -impl<'a, K> Iterator for NFromIndex<'a, RoTxn<'a>, K> +impl<'a, K> Iterator for NFromIndex<'a, RoTxn<'a, WithoutTls>, K> where K: Into + Serialize, { @@ -69,7 +69,7 @@ pub trait NFromIndexAdapter<'a, K: Into + Serialize>: impl<'a, I: Iterator>, K: Into + Serialize + 'a> NFromIndexAdapter<'a, K> for RoTraversalIterator<'a, I> { - type OutputIter = RoTraversalIterator<'a, NFromIndex<'a, RoTxn<'a>, K>>; + type OutputIter = RoTraversalIterator<'a, NFromIndex<'a, RoTxn<'a, WithoutTls>, K>>; #[inline] fn n_from_index(self, index: &'a str, key: &'a K) -> Self::OutputIter diff --git a/helixdb/src/helix_engine/graph_core/ops/util/filter_ref.rs b/helixdb/src/helix_engine/graph_core/ops/util/filter_ref.rs index d0876f0f..b03c5bbd 100644 --- a/helixdb/src/helix_engine/graph_core/ops/util/filter_ref.rs +++ b/helixdb/src/helix_engine/graph_core/ops/util/filter_ref.rs @@ -1,11 +1,11 @@ use crate::helix_engine::{graph_core::traversal_iter::RoTraversalIterator, types::GraphError}; use super::super::tr_val::TraversalVal; -use heed3::RoTxn; +use heed3::{RoTxn, WithoutTls}; pub struct FilterRef<'a, I, F> { iter: I, - txn: &'a RoTxn<'a>, + txn: &'a RoTxn<'a, WithoutTls>, f: F, } diff --git a/helixdb/src/helix_engine/graph_core/ops/util/map.rs b/helixdb/src/helix_engine/graph_core/ops/util/map.rs index 93a090b8..ae8d7f08 100644 --- a/helixdb/src/helix_engine/graph_core/ops/util/map.rs +++ b/helixdb/src/helix_engine/graph_core/ops/util/map.rs @@ -4,11 +4,11 @@ use crate::helix_engine::{ }; use super::super::tr_val::TraversalVal; -use heed3::RoTxn; +use heed3::{RoTxn, WithoutTls} ; pub struct Map<'a, I, F> { iter: I, - txn: &'a RoTxn<'a>, + txn: &'a RoTxn<'a, WithoutTls>, f: F, } @@ -16,7 +16,7 @@ pub struct Map<'a, I, F> { impl<'a, I, F> Iterator for Map<'a, I, F> where I: Iterator>, - F: FnMut(TraversalVal, &RoTxn<'a>) -> Result, + F: FnMut(TraversalVal, &RoTxn<'a, WithoutTls>) -> Result, { type Item = I::Item; @@ -51,7 +51,7 @@ pub trait MapAdapter<'a>: Iterator> { f: F, ) -> RoTraversalIterator<'a, impl Iterator>> where - F: FnMut(TraversalVal, &RoTxn<'a>) -> Result; + F: FnMut(TraversalVal, &RoTxn<'a, WithoutTls>) -> Result; } impl<'a, I: Iterator>> MapAdapter<'a> @@ -63,7 +63,7 @@ impl<'a, I: Iterator>> MapAdapter<'a> f: F, ) -> RoTraversalIterator<'a, impl Iterator>> where - F: FnMut(TraversalVal, &RoTxn<'a>) -> Result, + F: FnMut(TraversalVal, &RoTxn<'a, WithoutTls>) -> Result, { RoTraversalIterator { inner: Map { diff --git a/helixdb/src/helix_engine/graph_core/ops/util/paths.rs b/helixdb/src/helix_engine/graph_core/ops/util/paths.rs index cc5d5c7b..ccdf2588 100644 --- a/helixdb/src/helix_engine/graph_core/ops/util/paths.rs +++ b/helixdb/src/helix_engine/graph_core/ops/util/paths.rs @@ -6,7 +6,7 @@ use crate::{ }, protocol::{items::Edge, label_hash::hash_label}, }; -use heed3::RoTxn; +use heed3::{RoTxn, WithoutTls}; use std::{ collections::{HashMap, HashSet, VecDeque}, sync::Arc, @@ -23,7 +23,7 @@ pub struct ShortestPathIterator<'a, I> { path_type: PathType, edge_label: Option<&'a str>, storage: Arc, - txn: &'a RoTxn<'a>, + txn: &'a RoTxn<'a, WithoutTls>, } impl<'a, I: Iterator>> Iterator @@ -56,14 +56,14 @@ impl<'a, I: Iterator>> Iterator let mut current = end_id; while current != start_id { - nodes.push(self.storage.get_node(self.txn, current)?); + nodes.push(self.storage.get_node(&self.txn, current)?); let (prev_node, edge) = &parent[current]; edges.push(edge.clone()); current = prev_node; } - nodes.push(self.storage.get_node(self.txn, start_id)?); + nodes.push(self.storage.get_node(&self.txn, start_id)?); Ok(TraversalVal::Path((nodes, edges))) }; @@ -80,7 +80,7 @@ impl<'a, I: Iterator>> Iterator let iter = self .storage .out_edges_db - .prefix_iter(self.txn, &out_prefix) + .prefix_iter(&self.txn, &out_prefix) .unwrap(); for result in iter { @@ -90,7 +90,7 @@ impl<'a, I: Iterator>> Iterator if !visited.contains(&to_node) { visited.insert(to_node); - let edge = self.storage.get_edge(self.txn, &edge_id).unwrap(); // TODO: handle error + let edge = self.storage.get_edge(&self.txn, &edge_id).unwrap(); // TODO: handle error parent.insert(to_node, (current_id, edge)); if to_node == to { @@ -149,7 +149,7 @@ impl<'a, I: Iterator> + 'a> ShortestPath I: 'a, { let storage = Arc::clone(&self.storage); - let txn = self.txn; + let txn = &self.txn; RoTraversalIterator { inner: ShortestPathIterator { @@ -161,7 +161,7 @@ impl<'a, I: Iterator> + 'a> ShortestPath }, edge_label, storage, - txn, + txn: &txn, }, storage: Arc::clone(&self.storage), txn: self.txn, diff --git a/helixdb/src/helix_engine/graph_core/ops/util/props.rs b/helixdb/src/helix_engine/graph_core/ops/util/props.rs index c1ad7c97..4dbf6644 100644 --- a/helixdb/src/helix_engine/graph_core/ops/util/props.rs +++ b/helixdb/src/helix_engine/graph_core/ops/util/props.rs @@ -81,23 +81,23 @@ where } } -impl<'a, 'b, I> PropsAdapter<'a, I> for RwTraversalIterator<'a, 'b, I> -where - I: Iterator>, - 'b: 'a, -{ - #[inline] - fn check_property( - self, - prop: &'a str, - ) -> RoTraversalIterator<'a, impl Iterator>> { - RoTraversalIterator { - inner: PropsIterator { - iter: self.inner, - prop, - }, - storage: self.storage, - txn: self.txn, - } - } -} +// impl<'a, 'b, I> PropsAdapter<'a, I> for RwTraversalIterator<'a, 'b, I> +// where +// I: Iterator>, +// 'b: 'a, +// { +// #[inline] +// fn check_property( +// self, +// prop: &'a str, +// ) -> RoTraversalIterator<'a, impl Iterator>> { +// RoTraversalIterator { +// inner: PropsIterator { +// iter: self.inner, +// prop, +// }, +// storage: self.storage, +// txn: self.txn, +// } +// } +// } diff --git a/helixdb/src/helix_engine/graph_core/ops/vectors/search.rs b/helixdb/src/helix_engine/graph_core/ops/vectors/search.rs index be06a9e2..4ab900db 100644 --- a/helixdb/src/helix_engine/graph_core/ops/vectors/search.rs +++ b/helixdb/src/helix_engine/graph_core/ops/vectors/search.rs @@ -47,7 +47,7 @@ impl<'a, I: Iterator> + 'a> SearchVAdapt let vectors = self .storage .vectors - .search(self.txn, &query, k, filter, false); + .search(&self.txn, &query, k, filter, false); let iter = match vectors { Ok(vectors) => vectors diff --git a/helixdb/src/helix_engine/graph_core/traversal_iter.rs b/helixdb/src/helix_engine/graph_core/traversal_iter.rs index e53d2106..e83a9a55 100644 --- a/helixdb/src/helix_engine/graph_core/traversal_iter.rs +++ b/helixdb/src/helix_engine/graph_core/traversal_iter.rs @@ -1,18 +1,15 @@ use std::sync::Arc; -use heed3::{RoTxn, RwTxn}; +use heed3::{RoTxn, RwTxn, WithoutTls}; use super::ops::tr_val::TraversalVal; -use crate::helix_engine::{ - storage_core::storage_core::HelixGraphStorage, - types::GraphError, -}; +use crate::helix_engine::{storage_core::storage_core::HelixGraphStorage, types::GraphError}; use itertools::Itertools; pub struct RoTraversalIterator<'a, I> { pub inner: I, pub storage: Arc, - pub txn: &'a RoTxn<'a>, + pub txn: &'a RoTxn<'a, WithoutTls>, } // implementing iterator for TraversalIterator @@ -39,6 +36,27 @@ impl<'a, I: Iterator>> RoTraversalIterat .collect::() } + pub fn collect_parallel( + self + ) -> Result, GraphError> { + let iters = (0..8).map(|_| self.enumerate()).collect::>(); + + std::thread::scope(|s| { + let n = std::thread::available_parallelism().map(|n| n.get()).unwrap_or(8); // number of threads + + let threads: Vec<_> = iters + .into_iter() + .enumerate() + .map(|(x, iter)| s.spawn(move || iterate(n, x, iter))) + .collect(); + let results: Result, GraphError> = + threads.into_iter().map(|t| t.join().unwrap()).collect(); + + // Flatten all results + Ok(results?.into_iter().flatten().collect()) + }) + } + pub fn collect_to_obj(self) -> Option { self.inner.filter_map(|item| item.ok()).take(1).next() } @@ -69,6 +87,8 @@ impl<'scope, 'env, I: Iterator> RwTraversalIterator<'scope, 'env, I> { } } + + pub fn collect_to>(self) -> B where I: Iterator>, @@ -101,3 +121,31 @@ impl<'scope, 'env, I: Iterator> RwTraversalIterator<'scope, 'env, I> { // ) -> Option>; // } +fn iterate<'t>( + n: usize, // number of threads + x: usize, // thread ID + iter: impl Iterator)>, +) -> Result, GraphError> { + // i % n == x where + // i is the increment returned by the enumerator + // n is the total number or working threads and + // x is the thread ID on which we are. + let mut count = 0; + + let capacity = iter.size_hint().1.unwrap_or(0); + + let mut vals = Vec::with_capacity(capacity); + for (i, result) in iter { + if i % n == x { + let val = result?; + vals.push(val); + count += 1; + } + } + + eprintln!("thread {x} has seen {count} keys"); + + Ok(vals) +} + + diff --git a/helixdb/src/helix_engine/graph_core/traversal_tests.rs b/helixdb/src/helix_engine/graph_core/traversal_tests.rs index cc3eca29..b428aee7 100644 --- a/helixdb/src/helix_engine/graph_core/traversal_tests.rs +++ b/helixdb/src/helix_engine/graph_core/traversal_tests.rs @@ -1,7 +1,16 @@ use std::{sync::Arc, time::Instant}; use crate::{ - helix_engine::graph_core::ops::source::{n_from_index::NFromIndexAdapter, n_from_type::NFromTypeAdapter}, + helix_engine::graph_core::ops::source::{ + bulk_add_e::BulkAddEAdapter, e_from_type::EFromTypeAdapter, + }, + props, +}; +use crate::{ + helix_engine::graph_core::{ + ops::source::{n_from_index::NFromIndexAdapter, n_from_type::NFromTypeAdapter}, + traversal_iter::collect_parallel, + }, protocol::{ filterable::Filterable, id::ID, @@ -10,12 +19,6 @@ use crate::{ value::Value, }, }; -use crate::{ - helix_engine::graph_core::ops::source::{ - bulk_add_e::BulkAddEAdapter, e_from_type::EFromTypeAdapter, - }, - props, -}; use crate::{ helix_engine::{ graph_core::ops::{ @@ -52,1448 +55,1465 @@ fn setup_test_db() -> (Arc, TempDir) { (Arc::new(storage), temp_dir) } -#[test] -fn test_add_n() { - let (storage, _temp_dir) = setup_test_db(); +// #[test] +// fn test_add_n() { +// let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); +// let mut txn = storage.graph_env.write_txn().unwrap(); - let nodes = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props! { "name" => "John"}), None) - .filter_map(|node| node.ok()) - .collect::>(); +// let nodes = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props! { "name" => "John"}), None) +// .filter_map(|node| node.ok()) +// .collect::>(); + +// let node = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&nodes.first().unwrap().id()) +// .collect_to::>(); +// assert_eq!(node.first().unwrap().label(), "person"); +// println!("node: {:?}", node.first().unwrap()); + +// assert_eq!(node.first().unwrap().id(), nodes.first().unwrap().id()); +// assert_eq!( +// *node.first().unwrap().check_property("name").unwrap(), +// Value::String("John".to_string()) +// ); +// println!("node: {:?}", node.first().unwrap()); + +// // If we haven't dropped txn, ensure no borrows exist before commit +// txn.commit().unwrap(); +// } - let node = G::new(Arc::clone(&storage), &txn) - .n_from_id(&nodes.first().unwrap().id()) - .collect_to::>(); - assert_eq!(node.first().unwrap().label(), "person"); - println!("node: {:?}", node.first().unwrap()); - - assert_eq!(node.first().unwrap().id(), nodes.first().unwrap().id()); - assert_eq!( - *node.first().unwrap().check_property("name").unwrap(), - Value::String("John".to_string()) - ); - println!("node: {:?}", node.first().unwrap()); - - // If we haven't dropped txn, ensure no borrows exist before commit - txn.commit().unwrap(); -} +// #[test] +// fn test_add_e() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); -#[test] -fn test_add_e() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - let node1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let node1 = node1.first().unwrap(); - let node2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let node2 = node2.first().unwrap(); - - txn.commit().unwrap(); - let mut txn = storage.graph_env.write_txn().unwrap(); - let edges = G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - node1.id(), - node2.id(), - false, - EdgeType::Node, - ) - .filter_map(|edge| edge.ok()) - .collect::>(); - txn.commit().unwrap(); - // Check that the current step contains a single edge - match edges.first() { - Some(edge) => { - assert_eq!(edge.label(), "knows"); - match edge { - TraversalVal::Edge(edge) => { - assert_eq!(edge.from_node(), node1.id()); - assert_eq!(edge.to_node(), node2.id()); - } - _ => panic!("Expected Edge value"), - } - } - None => panic!("Expected SingleEdge value"), - } -} +// let node1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let node1 = node1.first().unwrap(); +// let node2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let node2 = node2.first().unwrap(); -#[test] -fn test_out() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - // Create graph: (person1)-[knows]->(person2)-[knows]->(person3) - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person1 = person1.first().unwrap(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person2 = person2.first().unwrap(); - let person3 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person3 = person3.first().unwrap(); - - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person1.id(), - person2.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person2.id(), - person3.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - - txn.commit().unwrap(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - // let nodes = VFromId::new(&storage, &txn, person1.id.as_str()) - // .out("knows") - // .filter_map(|node| node.ok()) - // .collect::>(); - let nodes = G::new(Arc::clone(&storage), &txn) - .n_from_id(&person1.id()) - .out("knows", &EdgeType::Node) - .filter_map(|node| node.ok()) - .collect::>(); +// txn.commit().unwrap(); +// let mut txn = storage.graph_env.write_txn().unwrap(); +// let edges = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// node1.id(), +// node2.id(), +// false, +// EdgeType::Node, +// ) +// .filter_map(|edge| edge.ok()) +// .collect::>(); +// txn.commit().unwrap(); +// // Check that the current step contains a single edge +// match edges.first() { +// Some(edge) => { +// assert_eq!(edge.label(), "knows"); +// match edge { +// TraversalVal::Edge(edge) => { +// assert_eq!(edge.from_node(), node1.id()); +// assert_eq!(edge.to_node(), node2.id()); +// } +// _ => panic!("Expected Edge value"), +// } +// } +// None => panic!("Expected SingleEdge value"), +// } +// } - // txn.commit().unwrap(); - // Check that current step is at person2 - assert_eq!(nodes.len(), 1); - assert_eq!(nodes[0].id(), person2.id()); -} +// #[test] +// fn test_out() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); -#[test] -fn test_out_e() { - let (storage, _temp_dir) = setup_test_db(); +// // Create graph: (person1)-[knows]->(person2)-[knows]->(person3) +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person1 = person1.first().unwrap(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person2 = person2.first().unwrap(); +// let person3 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person3 = person3.first().unwrap(); + +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person1.id(), +// person2.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person2.id(), +// person3.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); - // Create graph: (person1)-[knows]->(person2) +// txn.commit().unwrap(); +// let mut txn = storage.graph_env.write_txn().unwrap(); - let mut txn = storage.graph_env.write_txn().unwrap(); - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .filter_map(|node| node.ok()) - .collect::>(); - let person1 = person1.first().unwrap(); - txn.commit().unwrap(); - let mut txn = storage.graph_env.write_txn().unwrap(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .filter_map(|node| node.ok()) - .collect::>(); - let person2 = person2.first().unwrap(); - txn.commit().unwrap(); - let mut txn = storage.graph_env.write_txn().unwrap(); - let edge = G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person1.id().clone(), - person2.id().clone(), - false, - EdgeType::Node, - ) - .filter_map(|edge| edge.ok()) - .collect::>(); - let edge = edge.first().unwrap(); - // println!("traversal edge: {:?}", edge); - - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - println!("processing"); - let edges = G::new(Arc::clone(&storage), &txn) - .n_from_id(&person1.id()) - .out_e("knows") - .collect_to::>(); - println!("edges: {}", edges.len()); - - // Check that current step is at the edge between person1 and person2 - assert_eq!(edges.len(), 1); - assert_eq!(edges[0].id(), edge.id()); - assert_eq!(edges[0].label(), "knows"); -} +// // let nodes = VFromId::new(&storage, &txn, person1.id.as_str()) +// // .out("knows") +// // .filter_map(|node| node.ok()) +// // .collect::>(); +// let nodes = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&person1.id()) +// .out("knows", &EdgeType::Node) +// .filter_map(|node| node.ok()) +// .collect::>(); + +// // txn.commit().unwrap(); +// // Check that current step is at person2 +// assert_eq!(nodes.len(), 1); +// assert_eq!(nodes[0].id(), person2.id()); +// } -#[test] -fn test_in() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - // Create graph: (person1)-[knows]->(person2) - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person1 = person1.first().unwrap(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person2 = person2.first().unwrap(); - - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person1.id(), - person2.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let nodes = G::new(Arc::clone(&storage), &txn) - .n_from_id(&person2.id()) - .in_("knows", &EdgeType::Node) - .collect_to::>(); - - // Check that current step is at person1 - assert_eq!(nodes.len(), 1); - assert_eq!(nodes[0].id(), person1.id()); -} +// #[test] +// fn test_out_e() { +// let (storage, _temp_dir) = setup_test_db(); -#[test] -fn test_in_e() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - // Create test graph: (person1)-[knows]->(person2) - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person1 = person1.first().unwrap(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person2 = person2.first().unwrap(); - println!("person1: {:?}", person1); - println!("person2: {:?}", person2); - - let edge = G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person1.id(), - person2.id(), - true, - EdgeType::Node, - ) - .collect_to::>(); - let edge = edge.first().unwrap(); - println!("edge: {:?}", edge); - - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - - let edges = G::new(Arc::clone(&storage), &txn) - .n_from_id(&person2.id()) - .in_e("knows") - .collect_to::>(); - - // Check that current step is at the edge between person1 and person2 - assert_eq!(edges.len(), 1); - assert_eq!(edges[0].id(), edge.id()); - assert_eq!(edges[0].label(), "knows"); -} +// // Create graph: (person1)-[knows]->(person2) -#[test] -fn test_complex_traversal() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - // Graph structure: - // (person1)-[knows]->(person2)-[likes]->(person3) - // ^ | - // | | - // +-------<------[follows]------<-------+ - - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person1 = person1.first().unwrap(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person2 = person2.first().unwrap(); - let person3 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person3 = person3.first().unwrap(); - - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person1.id(), - person2.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "likes", - Some(props!()), - person2.id(), - person3.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "follows", - Some(props!()), - person3.id(), - person1.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - txn.commit().unwrap(); - - let txn = storage.graph_env.read_txn().unwrap(); - - let nodes = G::new(Arc::clone(&storage), &txn) - .n_from_id(&person1.id()) - .out("knows", &EdgeType::Node) - .collect_to::>(); - - // Check that current step is at person2 - assert_eq!(nodes.len(), 1); - assert_eq!(nodes[0].id(), person2.id()); - - // Traverse from person2 to person3 - let nodes = G::new_from(Arc::clone(&storage), &txn, vec![nodes[0].clone()]) - .out("likes", &EdgeType::Node) - .collect_to::>(); - - // Check that current step is at person3 - assert_eq!(nodes.len(), 1); - assert_eq!(nodes[0].id(), person3.id()); - - // Traverse from person3 to person1 - let nodes = G::new_from(Arc::clone(&storage), &txn, vec![nodes[0].clone()]) - .out("follows", &EdgeType::Node) - .collect_to::>(); - - // Check that current step is at person1 - assert_eq!(nodes.len(), 1); - assert_eq!(nodes[0].id(), person1.id()); -} +// let mut txn = storage.graph_env.write_txn().unwrap(); +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .filter_map(|node| node.ok()) +// .collect::>(); +// let person1 = person1.first().unwrap(); +// txn.commit().unwrap(); +// let mut txn = storage.graph_env.write_txn().unwrap(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .filter_map(|node| node.ok()) +// .collect::>(); +// let person2 = person2.first().unwrap(); +// txn.commit().unwrap(); +// let mut txn = storage.graph_env.write_txn().unwrap(); +// let edge = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person1.id().clone(), +// person2.id().clone(), +// false, +// EdgeType::Node, +// ) +// .filter_map(|edge| edge.ok()) +// .collect::>(); +// let edge = edge.first().unwrap(); +// // println!("traversal edge: {:?}", edge); -#[test] -fn test_count_single_node() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - let person = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person = person.first().unwrap(); - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let count = G::new(Arc::clone(&storage), &txn) - .n_from_id(&person.id()) - .count(); - - assert_eq!(count, 1); -} +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// println!("processing"); +// let edges = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&person1.id()) +// .out_e("knows") +// .collect_to::>(); +// println!("edges: {}", edges.len()); + +// // Check that current step is at the edge between person1 and person2 +// assert_eq!(edges.len(), 1); +// assert_eq!(edges[0].id(), edge.id()); +// assert_eq!(edges[0].label(), "knows"); +// } -#[test] -fn test_count_node_array() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - let _ = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let _ = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let _ = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let count = G::new(Arc::clone(&storage), &txn) - .n_from_type("person") // Get all nodes - .count(); - assert_eq!(count, 3); -} +// #[test] +// fn test_in() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); -#[test] -fn test_count_mixed_steps() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - // Create a graph with multiple paths - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person1 = person1.first().unwrap(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person2 = person2.first().unwrap(); - let person3 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person3 = person3.first().unwrap(); - - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person1.id(), - person2.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person1.id(), - person3.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - txn.commit().unwrap(); - println!( - "person1: {:?},\nperson2: {:?},\nperson3: {:?}", - person1, person2, person3 - ); - - let txn = storage.graph_env.read_txn().unwrap(); - let count = G::new(Arc::clone(&storage), &txn) - .n_from_id(&person1.id()) - .out("knows", &EdgeType::Node) - .count(); - - assert_eq!(count, 2); -} +// // Create graph: (person1)-[knows]->(person2) +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person1 = person1.first().unwrap(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person2 = person2.first().unwrap(); + +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person1.id(), +// person2.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let nodes = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&person2.id()) +// .in_("knows", &EdgeType::Node) +// .collect_to::>(); + +// // Check that current step is at person1 +// assert_eq!(nodes.len(), 1); +// assert_eq!(nodes[0].id(), person1.id()); +// } -#[test] -fn test_range_subset() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); +// #[test] +// fn test_in_e() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); - // Create multiple nodes - let _: Vec<_> = (0..5) - .map(|_| { - G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>() - .first() - .unwrap(); - }) - .collect(); +// // Create test graph: (person1)-[knows]->(person2) +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person1 = person1.first().unwrap(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person2 = person2.first().unwrap(); +// println!("person1: {:?}", person1); +// println!("person2: {:?}", person2); + +// let edge = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person1.id(), +// person2.id(), +// true, +// EdgeType::Node, +// ) +// .collect_to::>(); +// let edge = edge.first().unwrap(); +// println!("edge: {:?}", edge); - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let count = G::new(Arc::clone(&storage), &txn) - .n_from_type("person") // Get all nodes - .range(1, 3) // Take nodes at index 1 and 2 - .count(); +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); - assert_eq!(count, 2); -} +// let edges = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&person2.id()) +// .in_e("knows") +// .collect_to::>(); -#[test] -fn test_range_chaining() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - // Create graph: (p1)-[knows]->(p2)-[knows]->(p3)-[knows]->(p4)-[knows]->(p5) - let nodes: Vec<_> = (0..5) - .map(|i| { - G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props! { "name" => i }), None) - .collect_to::>() - .first() - .unwrap() - .clone() - }) - .collect(); - - // Create edges connecting nodes sequentially - for i in 0..4 { - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - nodes[i].id(), - nodes[i + 1].id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - } - - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - nodes[4].id(), - nodes[0].id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let count = G::new(Arc::clone(&storage), &txn) - .n_from_type("person") // Get all nodes - .range(0, 3) // Take first 3 nodes - .out("knows", &EdgeType::Node) // Get their outgoing nodes - .collect_to::>(); - - assert_eq!(count.len(), 3); -} +// // Check that current step is at the edge between person1 and person2 +// assert_eq!(edges.len(), 1); +// assert_eq!(edges[0].id(), edge.id()); +// assert_eq!(edges[0].label(), "knows"); +// } -#[test] -fn test_range_empty() { - let (storage, _temp_dir) = setup_test_db(); +// #[test] +// fn test_complex_traversal() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let count = G::new(Arc::clone(&storage), &txn) - .n_from_type("person") // Get all nodes - .range(0, 0) // Take first 3 nodes - .collect_to::>(); +// // Graph structure: +// // (person1)-[knows]->(person2)-[likes]->(person3) +// // ^ | +// // | | +// // +-------<------[follows]------<-------+ + +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person1 = person1.first().unwrap(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person2 = person2.first().unwrap(); +// let person3 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person3 = person3.first().unwrap(); + +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person1.id(), +// person2.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "likes", +// Some(props!()), +// person2.id(), +// person3.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "follows", +// Some(props!()), +// person3.id(), +// person1.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// txn.commit().unwrap(); - assert_eq!(count.len(), 0); -} +// let txn = storage.graph_env.read_txn().unwrap(); -#[test] -fn test_count_empty() { - let (storage, _temp_dir) = setup_test_db(); - let txn = storage.graph_env.read_txn().unwrap(); - let count = G::new(Arc::clone(&storage), &txn) - .n_from_type("person") // Get all nodes - .range(0, 0) // Take first 3 nodes - .count(); +// let nodes = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&person1.id()) +// .out("knows", &EdgeType::Node) +// .collect_to::>(); - assert_eq!(count, 0); -} +// // Check that current step is at person2 +// assert_eq!(nodes.len(), 1); +// assert_eq!(nodes[0].id(), person2.id()); -#[test] -fn test_n_from_id() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); +// // Traverse from person2 to person3 +// let nodes = G::new_from(Arc::clone(&storage), &txn, vec![nodes[0].clone()]) +// .out("likes", &EdgeType::Node) +// .collect_to::>(); - // Create a test node - let person = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let node_id = person.id().clone(); +// // Check that current step is at person3 +// assert_eq!(nodes.len(), 1); +// assert_eq!(nodes[0].id(), person3.id()); - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let count = G::new(Arc::clone(&storage), &txn) - .n_from_id(&node_id) - .collect_to::>(); +// // Traverse from person3 to person1 +// let nodes = G::new_from(Arc::clone(&storage), &txn, vec![nodes[0].clone()]) +// .out("follows", &EdgeType::Node) +// .collect_to::>(); - assert_eq!(count.len(), 1); -} +// // Check that current step is at person1 +// assert_eq!(nodes.len(), 1); +// assert_eq!(nodes[0].id(), person1.id()); +// } -#[test] -fn test_n_from_id_with_traversal() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - // Create test graph: (person1)-[knows]->(person2) - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person1.id(), - person2.id(), - true, - EdgeType::Node, - ) - .collect_to::>(); - - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let count = G::new(Arc::clone(&storage), &txn) - .n_from_id(&person1.id()) - .out("knows", &EdgeType::Node) - .collect_to::>(); - - // Check that traversal reaches person2 - assert_eq!(count.len(), 1); - assert_eq!(count[0].id(), person2.id()); -} +// #[test] +// fn test_count_single_node() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); +// let person = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person = person.first().unwrap(); +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let count = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&person.id()) +// .count(); -#[test] -fn test_e_from_id() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - // Create test graph and edge - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let edge = G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person1.id(), - person2.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - let edge_id = edge.first().unwrap().id(); - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let edges = G::new(Arc::clone(&storage), &txn) - .e_from_id(&edge_id) - .collect_to::>(); - - // Check that the current step contains the correct single edge - assert_eq!(edges.len(), 1); - assert_eq!(edges[0].id(), edge_id); - assert_eq!(edges[0].label(), "knows"); - if let Some(TraversalVal::Edge(edge)) = edges.first() { - assert_eq!(edge.from_node(), person1.id()); - assert_eq!(edge.to_node(), person2.id()); - } else { - assert!(false, "Expected Edge value"); - } -} +// assert_eq!(count, 1); +// } -#[test] -fn test_n_from_id_nonexistent() { - let (storage, _temp_dir) = setup_test_db(); - let txn = storage.graph_env.read_txn().unwrap(); - let nodes = G::new(Arc::clone(&storage), &txn) - .n_from_id(&100) - .collect_to::>(); - assert!(nodes.is_empty()); -} +// #[test] +// fn test_count_node_array() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); +// let _ = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let _ = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let _ = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); -#[test] -fn test_e_from_id_nonexistent() { - let (storage, _temp_dir) = setup_test_db(); - let txn = storage.graph_env.read_txn().unwrap(); - let edges = G::new(Arc::clone(&storage), &txn) - .e_from_id(&100) - .collect_to::>(); - assert!(edges.is_empty()); -} +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let count = G::new(Arc::clone(&storage), &txn) +// .n_from_type("person") // Get all nodes +// .count(); +// assert_eq!(count, 3); +// } -#[test] -fn test_n_from_id_chain_operations() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - // Create test graph: (person1)-[knows]->(person2)-[likes]->(person3) - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person3 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person3 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person1.id(), - person2.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "likes", - Some(props!()), - person2.id(), - person3.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let nodes = G::new(Arc::clone(&storage), &txn) - .n_from_id(&person1.id()) - .out("knows", &EdgeType::Node) - .out("likes", &EdgeType::Node) - .collect_to::>(); - - // Check that the chain of traversals reaches person3 - assert_eq!(nodes.len(), 1); - assert_eq!(nodes[0].id(), person3.id()); -} +// #[test] +// fn test_count_mixed_steps() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); -#[test] -fn test_e_from_id_chain_operations() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - // Create test graph and edges - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person3 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - - let edge1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person2.id(), - person1.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "likes", - Some(props!()), - person2.id(), - person3.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let nodes = G::new(Arc::clone(&storage), &txn) - .e_from_id(&edge1.id()) - .from_n() - .collect_to::>(); - - assert_eq!(nodes.len(), 1); - assert_eq!(nodes[0].id(), person2.id()); - assert_eq!(nodes[0].label(), "person"); -} +// // Create a graph with multiple paths +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person1 = person1.first().unwrap(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person2 = person2.first().unwrap(); +// let person3 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person3 = person3.first().unwrap(); + +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person1.id(), +// person2.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person1.id(), +// person3.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// txn.commit().unwrap(); +// println!( +// "person1: {:?},\nperson2: {:?},\nperson3: {:?}", +// person1, person2, person3 +// ); -#[test] -fn test_filter_nodes() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - // Create nodes with different properties - let _ = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props! { "age" => 25 }), None) - .collect_to::>(); - let _ = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props! { "age" => 30 }), None) - .collect_to::>(); - let person3 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props! { "age" => 35 }), None) - .collect_to::>(); - - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - - let traversal = G::new(Arc::clone(&storage), &txn) - .n_from_type("person") - .filter_ref(|val, _| { - if let Ok(TraversalVal::Node(node)) = val { - if let Ok(value) = node.check_property("age") { - match value { - Value::F64(age) => Ok(*age > 30.0), - Value::I32(age) => Ok(*age > 30), - _ => Ok(false), - } - } else { - Ok(false) - } - } else { - Ok(false) - } - }) - .collect_to::>(); - assert_eq!(traversal.len(), 1); - assert_eq!(traversal[0].id(), person3.id()); -} +// let txn = storage.graph_env.read_txn().unwrap(); +// let count = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&person1.id()) +// .out("knows", &EdgeType::Node) +// .count(); -#[test] -fn test_filter_macro_single_argument() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - let _ = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props! { "name" => "Alice" }), None) - .collect_to::>(); - let _ = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props! { "name" => "Bob" }), None) - .collect_to::>(); - - fn has_name(val: &Result) -> Result { - if let Ok(TraversalVal::Node(node)) = val { - return node.check_property("name").map_or(Ok(false), |_| Ok(true)); - } else { - return Ok(false); - } - } - - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let traversal = G::new(Arc::clone(&storage), &txn) - .n_from_type("person") - .filter_ref(|val, _| has_name(val)) - .collect_to::>(); - assert_eq!(traversal.len(), 2); - assert!(traversal - .iter() - .any(|val| if let TraversalVal::Node(node) = val { - let name = node.check_property("name").unwrap(); - name == &Value::String("Alice".to_string()) || name == &Value::String("Bob".to_string()) - } else { - false - })); -} +// assert_eq!(count, 2); +// } -#[test] -fn test_filter_macro_multiple_arguments() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - let _ = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props! { "age" => 25 }), None) - .collect_to::>(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props! { "age" => 30 }), None) - .collect_to::>(); - txn.commit().unwrap(); - - fn age_greater_than( - val: &Result, - min_age: i32, - ) -> Result { - if let Ok(TraversalVal::Node(node)) = val { - if let Ok(value) = node.check_property("age") { - match value { - Value::F64(age) => Ok(*age > min_age as f64), - Value::I32(age) => Ok(*age > min_age), - _ => Ok(false), - } - } else { - Ok(false) - } - } else { - Ok(false) - } - } - - let txn = storage.graph_env.read_txn().unwrap(); - let traversal = G::new(Arc::clone(&storage), &txn) - .n_from_type("person") - .filter_ref(|val, _| age_greater_than(val, 27)) - .collect_to::>(); - - assert_eq!(traversal.len(), 1); - assert_eq!(traversal[0].id(), person2.id()); -} +// #[test] +// fn test_range_subset() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); -#[test] -fn test_filter_edges() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - - let _ = G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props! { "since" => 2020 }), - person1.id(), - person2.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - let edge2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props! { "since" => 2022 }), - person2.id(), - person1.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - - fn recent_edge(val: &Result, year: i32) -> Result { - if let Ok(TraversalVal::Edge(edge)) = val { - if let Ok(value) = edge.check_property("since") { - match value { - Value::I32(since) => return Ok(*since > year), - Value::F64(since) => return Ok(*since > year as f64), - _ => return Ok(false), - } - } else { - Ok(false) - } - } else { - Ok(false) - } - } - - let traversal = G::new(Arc::clone(&storage), &txn) - .e_from_type("knows") - .filter_ref(|val, _| recent_edge(val, 2021)) - .collect_to::>(); - - assert_eq!(traversal.len(), 1); - assert_eq!(traversal[0].id(), edge2.id()); -} +// // Create multiple nodes +// let _: Vec<_> = (0..5) +// .map(|_| { +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>() +// .first() +// .unwrap(); +// }) +// .collect(); -#[test] -fn test_filter_empty_result() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - let _ = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props! { "age" => 25 }), None) - .collect_to::>(); - - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let traversal = G::new(Arc::clone(&storage), &txn) - .n_from_type("person") - .filter_ref(|val, _| { - if let Ok(TraversalVal::Node(node)) = val { - if let Ok(value) = node.check_property("age") { - match value { - Value::I32(age) => return Ok(*age > 100), - Value::F64(age) => return Ok(*age > 100.0), - _ => return Ok(false), - } - } else { - Ok(false) - } - } else { - Ok(false) - } - }) - .collect_to::>(); - assert!(traversal.is_empty()); -} +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let count = G::new(Arc::clone(&storage), &txn) +// .n_from_type("person") // Get all nodes +// .range(1, 3) // Take nodes at index 1 and 2 +// .count(); -#[test] -fn test_filter_chain() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - let _ = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n( - "person", - Some(props! { "age" => 25, "name" => "Alice" }), - None, - ) - .collect_to_val(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n( - "person", - Some(props! { "age" => 30, "name" => "Bob" }), - None, - ) - .collect_to_val(); - let _ = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props! { "age" => 35 }), None) - .collect_to_val(); - - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - - fn has_name(val: &Result) -> Result { - if let Ok(TraversalVal::Node(node)) = val { - return node.check_property("name").map_or(Ok(false), |_| Ok(true)); - } else { - return Ok(false); - } - } - - fn age_greater_than( - val: &Result, - min_age: i32, - ) -> Result { - if let Ok(TraversalVal::Node(node)) = val { - if let Ok(value) = node.check_property("age") { - match value { - Value::F64(age) => return Ok(*age > min_age as f64), - Value::I32(age) => return Ok(*age > min_age), - _ => return Ok(false), - } - } else { - return Ok(false); - } - } else { - return Ok(false); - } - } - - let traversal = G::new(Arc::clone(&storage), &txn) - .n_from_type("person") - .filter_ref(|val, _| has_name(val)) - .filter_ref(|val, _| age_greater_than(val, 27)) - .collect_to::>(); - - assert_eq!(traversal.len(), 1); - assert_eq!(traversal[0].id(), person2.id()); -} +// assert_eq!(count, 2); +// } -#[test] -fn test_in_n() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("per son", Some(props!()), None) - .collect_to_val(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to_val(); - - let edge = G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person1.id(), - person2.id(), - false, - EdgeType::Node, - ) - .collect_to_val(); - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let traversal = G::new(Arc::clone(&storage), &txn) - .e_from_id(&edge.id()) - .to_n() - .collect_to::>(); - - assert_eq!(traversal.len(), 1); - assert_eq!(traversal[0].id(), person2.id()); -} +// #[test] +// fn test_range_chaining() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); -#[test] -fn test_out_n() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - let person1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to_val(); - let person2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to_val(); - - let edge = G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - Some(props!()), - person1.id(), - person2.id(), - false, - EdgeType::Node, - ) - .collect_to_val(); - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let traversal = G::new(Arc::clone(&storage), &txn) - .e_from_id(&edge.id()) - .from_n() - .collect_to::>(); - assert_eq!(traversal.len(), 1); - assert_eq!(traversal[0].id(), person1.id()); -} +// // Create graph: (p1)-[knows]->(p2)-[knows]->(p3)-[knows]->(p4)-[knows]->(p5) +// let nodes: Vec<_> = (0..5) +// .map(|i| { +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props! { "name" => i }), None) +// .collect_to::>() +// .first() +// .unwrap() +// .clone() +// }) +// .collect(); -#[test] -fn test_edge_properties() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - let node1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to::>(); - let node1 = node1.first().unwrap().clone(); - let node2 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to_val(); - let props = Some(props! { "since" => 2020, "date" => 1744965900, "name" => "hello"}); - let edge = G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - props.clone(), - node1.id(), - node2.id(), - false, - EdgeType::Node, - ) - .collect_to::>(); - - txn.commit().unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let edge = G::new_from(Arc::clone(&storage), &txn, vec![node1]) - .out_e("knows") - .filter_ref(|val, _| { - if let Ok(val) = val { - println!("val: {:?}", val.check_property("date")); - val.check_property("date").map_or(Ok(false), |v| { - println!("v: {:?}", v); - println!("v: {:?}", *v == 1743290007); - Ok(*v >= 1743290007) - }) - } else { - Ok(false) - } - }) - .collect_to::>(); - let edge = edge.first().unwrap(); - match edge { - TraversalVal::Edge(edge) => { - assert_eq!( - edge.properties.clone().unwrap(), - props.unwrap().into_iter().collect() - ); - } - _ => { - panic!("Expected Edge value"); - } - } -} +// // Create edges connecting nodes sequentially +// for i in 0..4 { +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// nodes[i].id(), +// nodes[i + 1].id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// } + +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// nodes[4].id(), +// nodes[0].id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let count = G::new(Arc::clone(&storage), &txn) +// .n_from_type("person") // Get all nodes +// .range(0, 3) // Take first 3 nodes +// .out("knows", &EdgeType::Node) // Get their outgoing nodes +// .collect_to::>(); + +// assert_eq!(count.len(), 3); +// } + +// #[test] +// fn test_range_empty() { +// let (storage, _temp_dir) = setup_test_db(); + +// let txn = storage.graph_env.read_txn().unwrap(); +// let count = G::new(Arc::clone(&storage), &txn) +// .n_from_type("person") // Get all nodes +// .range(0, 0) // Take first 3 nodes +// .collect_to::>(); + +// assert_eq!(count.len(), 0); +// } // #[test] -// fn test_shortest_mutual_path() { +// fn test_count_empty() { +// let (storage, _temp_dir) = setup_test_db(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let count = G::new(Arc::clone(&storage), &txn) +// .n_from_type("person") // Get all nodes +// .range(0, 0) // Take first 3 nodes +// .count(); + +// assert_eq!(count, 0); +// } + +// #[test] +// fn test_n_from_id() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// // Create a test node +// let person = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let node_id = person.id().clone(); + +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let count = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&node_id) +// .collect_to::>(); + +// assert_eq!(count.len(), 1); +// } + +// #[test] +// fn test_n_from_id_with_traversal() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// // Create test graph: (person1)-[knows]->(person2) +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person1.id(), +// person2.id(), +// true, +// EdgeType::Node, +// ) +// .collect_to::>(); + +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let count = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&person1.id()) +// .out("knows", &EdgeType::Node) +// .collect_to::>(); + +// // Check that traversal reaches person2 +// assert_eq!(count.len(), 1); +// assert_eq!(count[0].id(), person2.id()); +// } + +// #[test] +// fn test_e_from_id() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// // Create test graph and edge +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let edge = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person1.id(), +// person2.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// let edge_id = edge.first().unwrap().id(); +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let edges = G::new(Arc::clone(&storage), &txn) +// .e_from_id(&edge_id) +// .collect_to::>(); + +// // Check that the current step contains the correct single edge +// assert_eq!(edges.len(), 1); +// assert_eq!(edges[0].id(), edge_id); +// assert_eq!(edges[0].label(), "knows"); +// if let Some(TraversalVal::Edge(edge)) = edges.first() { +// assert_eq!(edge.from_node(), person1.id()); +// assert_eq!(edge.to_node(), person2.id()); +// } else { +// assert!(false, "Expected Edge value"); +// } +// } + +// #[test] +// fn test_n_from_id_nonexistent() { +// let (storage, _temp_dir) = setup_test_db(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let nodes = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&100) +// .collect_to::>(); +// assert!(nodes.is_empty()); +// } + +// #[test] +// fn test_e_from_id_nonexistent() { +// let (storage, _temp_dir) = setup_test_db(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let edges = G::new(Arc::clone(&storage), &txn) +// .e_from_id(&100) +// .collect_to::>(); +// assert!(edges.is_empty()); +// } + +// #[test] +// fn test_n_from_id_chain_operations() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// // Create test graph: (person1)-[knows]->(person2)-[likes]->(person3) +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person3 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person3 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); + +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person1.id(), +// person2.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "likes", +// Some(props!()), +// person2.id(), +// person3.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); + +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let nodes = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&person1.id()) +// .out("knows", &EdgeType::Node) +// .out("likes", &EdgeType::Node) +// .collect_to::>(); + +// // Check that the chain of traversals reaches person3 +// assert_eq!(nodes.len(), 1); +// assert_eq!(nodes[0].id(), person3.id()); +// } + +// #[test] +// fn test_e_from_id_chain_operations() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// // Create test graph and edges +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person3 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); + +// let edge1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person2.id(), +// person1.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "likes", +// Some(props!()), +// person2.id(), +// person3.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); + +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let nodes = G::new(Arc::clone(&storage), &txn) +// .e_from_id(&edge1.id()) +// .from_n() +// .collect_to::>(); + +// assert_eq!(nodes.len(), 1); +// assert_eq!(nodes[0].id(), person2.id()); +// assert_eq!(nodes[0].label(), "person"); +// } + +// #[test] +// fn test_filter_nodes() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// // Create nodes with different properties +// let _ = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props! { "age" => 25 }), None) +// .collect_to::>(); +// let _ = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props! { "age" => 30 }), None) +// .collect_to::>(); +// let person3 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props! { "age" => 35 }), None) +// .collect_to::>(); + +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); + +// let traversal = G::new(Arc::clone(&storage), &txn) +// .n_from_type("person") +// .filter_ref(|val, _| { +// if let Ok(TraversalVal::Node(node)) = val { +// if let Ok(value) = node.check_property("age") { +// match value { +// Value::F64(age) => Ok(*age > 30.0), +// Value::I32(age) => Ok(*age > 30), +// _ => Ok(false), +// } +// } else { +// Ok(false) +// } +// } else { +// Ok(false) +// } +// }) +// .collect_to::>(); +// assert_eq!(traversal.len(), 1); +// assert_eq!(traversal[0].id(), person3.id()); +// } + +// #[test] +// fn test_filter_macro_single_argument() { // let (storage, _temp_dir) = setup_test_db(); // let mut txn = storage.graph_env.write_txn().unwrap(); -// // Create a complex network of mutual and one-way connections -// // Mutual: Alice <-> Bob <-> Charlie <-> David -// // One-way: Alice -> Eve -> David -// let users: Vec = vec!["alice", "bob", "charlie", "dave", "eve"] +// let _ = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props! { "name" => "Alice" }), None) +// .collect_to::>(); +// let _ = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props! { "name" => "Bob" }), None) +// .collect_to::>(); + +// fn has_name(val: &Result) -> Result { +// if let Ok(TraversalVal::Node(node)) = val { +// return node.check_property("name").map_or(Ok(false), |_| Ok(true)); +// } else { +// return Ok(false); +// } +// } + +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let traversal = G::new(Arc::clone(&storage), &txn) +// .n_from_type("person") +// .filter_ref(|val, _| has_name(val)) +// .collect_to::>(); +// assert_eq!(traversal.len(), 2); +// assert!(traversal // .iter() -// .map(|name| { -// storage -// .create_node(&mut txn, "person", Some(props! ){ "name" => *name }, None, None) -// .unwrap() +// .any(|val| if let TraversalVal::Node(node) = val { +// let name = node.check_property("name").unwrap(); +// name == &Value::String("Alice".to_string()) || name == &Value::String("Bob".to_string()) +// } else { +// false +// })); +// } + +// #[test] +// fn test_filter_macro_multiple_arguments() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// let _ = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props! { "age" => 25 }), None) +// .collect_to::>(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props! { "age" => 30 }), None) +// .collect_to::>(); +// txn.commit().unwrap(); + +// fn age_greater_than( +// val: &Result, +// min_age: i32, +// ) -> Result { +// if let Ok(TraversalVal::Node(node)) = val { +// if let Ok(value) = node.check_property("age") { +// match value { +// Value::F64(age) => Ok(*age > min_age as f64), +// Value::I32(age) => Ok(*age > min_age), +// _ => Ok(false), +// } +// } else { +// Ok(false) +// } +// } else { +// Ok(false) +// } +// } + +// let txn = storage.graph_env.read_txn().unwrap(); +// let traversal = G::new(Arc::clone(&storage), &txn) +// .n_from_type("person") +// .filter_ref(|val, _| age_greater_than(val, 27)) +// .collect_to::>(); + +// assert_eq!(traversal.len(), 1); +// assert_eq!(traversal[0].id(), person2.id()); +// } + +// #[test] +// fn test_filter_edges() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); + +// let _ = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props! { "since" => 2020 }), +// person1.id(), +// person2.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); +// let edge2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props! { "since" => 2022 }), +// person2.id(), +// person1.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); + +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); + +// fn recent_edge(val: &Result, year: i32) -> Result { +// if let Ok(TraversalVal::Edge(edge)) = val { +// if let Ok(value) = edge.check_property("since") { +// match value { +// Value::I32(since) => return Ok(*since > year), +// Value::F64(since) => return Ok(*since > year as f64), +// _ => return Ok(false), +// } +// } else { +// Ok(false) +// } +// } else { +// Ok(false) +// } +// } + +// let traversal = G::new(Arc::clone(&storage), &txn) +// .e_from_type("knows") +// .filter_ref(|val, _| recent_edge(val, 2021)) +// .collect_to::>(); + +// assert_eq!(traversal.len(), 1); +// assert_eq!(traversal[0].id(), edge2.id()); +// } + +// #[test] +// fn test_filter_empty_result() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// let _ = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props! { "age" => 25 }), None) +// .collect_to::>(); + +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let traversal = G::new(Arc::clone(&storage), &txn) +// .n_from_type("person") +// .filter_ref(|val, _| { +// if let Ok(TraversalVal::Node(node)) = val { +// if let Ok(value) = node.check_property("age") { +// match value { +// Value::I32(age) => return Ok(*age > 100), +// Value::F64(age) => return Ok(*age > 100.0), +// _ => return Ok(false), +// } +// } else { +// Ok(false) +// } +// } else { +// Ok(false) +// } // }) -// .collect(); +// .collect_to::>(); +// assert!(traversal.is_empty()); +// } -// for (i, j) in [(0, 1), (1, 2), (2, 3)].iter() { -// storage -// .create_edge(&mut txn, "knows", &users[*i].id, &users[*j].id, Some(props!())) -// .unwrap(); -// storage -// .create_edge(&mut txn, "knows", &users[*j].id, &users[*i].id, Some(props!())) -// .unwrap(); +// #[test] +// fn test_filter_chain() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// let _ = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n( +// "person", +// Some(props! { "age" => 25, "name" => "Alice" }), +// None, +// ) +// .collect_to_val(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n( +// "person", +// Some(props! { "age" => 30, "name" => "Bob" }), +// None, +// ) +// .collect_to_val(); +// let _ = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props! { "age" => 35 }), None) +// .collect_to_val(); + +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); + +// fn has_name(val: &Result) -> Result { +// if let Ok(TraversalVal::Node(node)) = val { +// return node.check_property("name").map_or(Ok(false), |_| Ok(true)); +// } else { +// return Ok(false); +// } +// } + +// fn age_greater_than( +// val: &Result, +// min_age: i32, +// ) -> Result { +// if let Ok(TraversalVal::Node(node)) = val { +// if let Ok(value) = node.check_property("age") { +// match value { +// Value::F64(age) => return Ok(*age > min_age as f64), +// Value::I32(age) => return Ok(*age > min_age), +// _ => return Ok(false), +// } +// } else { +// return Ok(false); +// } +// } else { +// return Ok(false); +// } // } -// storage -// .create_edge(&mut txn, "knows", &users[0].id, &users[4].id, Some(props!())) -// .unwrap(); -// storage -// .create_edge(&mut txn, "knows", &users[4].id, &users[3].id, Some(props!())) -// .unwrap(); +// let traversal = G::new(Arc::clone(&storage), &txn) +// .n_from_type("person") +// .filter_ref(|val, _| has_name(val)) +// .filter_ref(|val, _| age_greater_than(val, 27)) +// .collect_to::>(); + +// assert_eq!(traversal.len(), 1); +// assert_eq!(traversal[0].id(), person2.id()); +// } +// #[test] +// fn test_in_n() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("per son", Some(props!()), None) +// .collect_to_val(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to_val(); + +// let edge = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person1.id(), +// person2.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to_val(); // txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let traversal = G::new(Arc::clone(&storage), &txn) +// .e_from_id(&edge.id()) +// .to_n() +// .collect_to::>(); +// assert_eq!(traversal.len(), 1); +// assert_eq!(traversal[0].id(), person2.id()); +// } + +// #[test] +// fn test_out_n() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// let person1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to_val(); +// let person2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to_val(); + +// let edge = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// Some(props!()), +// person1.id(), +// person2.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to_val(); +// txn.commit().unwrap(); // let txn = storage.graph_env.read_txn().unwrap(); -// let mut tr = -// TraversalBuilder::new(Arc::clone(&storage), TraversalValue::from(users[0].clone())); -// tr.shortest_mutual_path_to(&txn, &users[3].id); +// let traversal = G::new(Arc::clone(&storage), &txn) +// .e_from_id(&edge.id()) +// .from_n() +// .collect_to::>(); +// assert_eq!(traversal.len(), 1); +// assert_eq!(traversal[0].id(), person1.id()); +// } -// let result = tr.result(txn); -// let paths = match result.unwrap() { -// TraversalValue::Paths(paths) => paths, +// #[test] +// fn test_edge_properties() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// let node1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to::>(); +// let node1 = node1.first().unwrap().clone(); +// let node2 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to_val(); +// let props = Some(props! { "since" => 2020, "date" => 1744965900, "name" => "hello"}); +// let edge = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// props.clone(), +// node1.id(), +// node2.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to::>(); + +// txn.commit().unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let edge = G::new_from(Arc::clone(&storage), &txn, vec![node1]) +// .out_e("knows") +// .filter_ref(|val, _| { +// if let Ok(val) = val { +// println!("val: {:?}", val.check_property("date")); +// val.check_property("date").map_or(Ok(false), |v| { +// println!("v: {:?}", v); +// println!("v: {:?}", *v == 1743290007); +// Ok(*v >= 1743290007) +// }) +// } else { +// Ok(false) +// } +// }) +// .collect_to::>(); +// let edge = edge.first().unwrap(); +// match edge { +// TraversalVal::Edge(edge) => { +// assert_eq!( +// edge.properties.clone().unwrap(), +// props.unwrap().into_iter().collect() +// ); +// } // _ => { -// panic!("Expected PathArray value") +// panic!("Expected Edge value"); // } +// } +// } + +// // #[test] +// // fn test_shortest_mutual_path() { +// // let (storage, _temp_dir) = setup_test_db(); +// // let mut txn = storage.graph_env.write_txn().unwrap(); + +// // // Create a complex network of mutual and one-way connections +// // // Mutual: Alice <-> Bob <-> Charlie <-> David +// // // One-way: Alice -> Eve -> David +// // let users: Vec = vec!["alice", "bob", "charlie", "dave", "eve"] +// // .iter() +// // .map(|name| { +// // storage +// // .create_node(&mut txn, "person", Some(props! ){ "name" => *name }, None, None) +// // .unwrap() +// // }) +// // .collect(); + +// // for (i, j) in [(0, 1), (1, 2), (2, 3)].iter() { +// // storage +// // .create_edge(&mut txn, "knows", &users[*i].id, &users[*j].id, Some(props!())) +// // .unwrap(); +// // storage +// // .create_edge(&mut txn, "knows", &users[*j].id, &users[*i].id, Some(props!())) +// // .unwrap(); +// // } + +// // storage +// // .create_edge(&mut txn, "knows", &users[0].id, &users[4].id, Some(props!())) +// // .unwrap(); +// // storage +// // .create_edge(&mut txn, "knows", &users[4].id, &users[3].id, Some(props!())) +// // .unwrap(); + +// // txn.commit().unwrap(); + +// // let txn = storage.graph_env.read_txn().unwrap(); +// // let mut tr = +// // TraversalBuilder::new(Arc::clone(&storage), TraversalValue::from(users[0].clone())); +// // tr.shortest_mutual_path_to(&txn, &users[3].id); + +// // let result = tr.result(txn); +// // let paths = match result.unwrap() { +// // TraversalValue::Paths(paths) => paths, +// // _ => { +// // panic!("Expected PathArray value") +// // } +// // }; + +// // assert_eq!(paths.len(), 1); +// // let (nodes, edges) = &paths[0]; + +// // assert_eq!(nodes.len(), 4); +// // assert_eq!(edges.len(), 3); +// // assert_eq!(nodes[0].id, users[3].id); // David +// // assert_eq!(nodes[1].id, users[2].id); // Charlie +// // assert_eq!(nodes[2].id, users[1].id); // Bob +// // assert_eq!(nodes[3].id, users[0].id); // Alice +// // } + +// #[test] +// fn huge_traversal() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// let mut nodes = Vec::with_capacity(65_000_000); +// let mut start = Instant::now(); + +// for i in 0..100_000 { +// // nodes.push(Node::new("person", Some(props! ){ "name" => i})); +// nodes.push(v6_uuid()); +// } +// println!("time taken to initialise nodes: {:?}", start.elapsed()); +// start = Instant::now(); + +// println!("time taken to sort nodes: {:?}", start.elapsed()); +// start = Instant::now(); +// let now = Instant::now(); +// let res = G::new_mut(Arc::clone(&storage), &mut txn) +// .bulk_add_n(&mut nodes, None, 1000000) +// .map(|res| res.unwrap()) +// .collect::>(); +// txn.commit().unwrap(); +// println!("time taken to add nodes: {:?}", now.elapsed()); +// let start = Instant::now(); +// let mut edges = Vec::with_capacity(6000 * 2000); +// for i in 0..10_000 { +// let random_node1 = &nodes[rand::rng().random_range(0..nodes.len())]; +// let random_node2 = &nodes[rand::rng().random_range(0..nodes.len())]; +// // edges.push(Edge { +// // id: v6_uuid(), +// // label: "knows".to_string(), +// // properties: HashMap::new(), +// // from_node: random_node1.id, +// // to_node: random_node2.id, +// // }); +// edges.push((*random_node1, *random_node2, v6_uuid())); +// } +// println!( +// "time taken to create {} edges: {:?}", +// edges.len(), +// start.elapsed() +// ); +// let mut start = Instant::now(); +// let mut txn = storage.graph_env.write_txn().unwrap(); +// let res = G::new_mut(Arc::clone(&storage), &mut txn) +// .bulk_add_e(edges, false, 1000000) +// .map(|res| res.unwrap()) +// .collect::>(); +// txn.commit().unwrap(); +// println!("time taken to add edges: {:?}", start.elapsed()); + +// let txn = storage.graph_env.read_txn().unwrap(); +// let now = Instant::now(); +// let traversal = G::new(Arc::clone(&storage), &txn) +// .n_from_type("user") +// .out_e("knows") +// .to_n() +// .out("knows", &EdgeType::Node) +// // .filter_ref(|val, _| { +// // if let Ok(TraversalVal::Node(node)) = val { +// // if let Some(value) = node.check_property("name") { +// // match value { +// // Value::I32(name) => return *name < 700000, +// // _ => return false, +// // } +// // } else { +// // return false; +// // } +// // } else { +// // return false; +// // } +// // }) +// .out("knows", &EdgeType::Node) +// .out("knows", &EdgeType::Node) +// .out("knows", &EdgeType::Node) +// .out("knows", &EdgeType::Node) +// .dedup() +// .range(0, 10000) +// .count(); +// println!("optimized version time: {:?}", now.elapsed()); +// println!("traversal: {:?}", traversal); +// println!( +// "size of mdb file on disk: {:?}", +// storage.graph_env.real_disk_size() +// ); +// txn.commit().unwrap(); + +// // let txn = storage.graph_env.read_txn().unwrap(); +// // let now = Instant::now(); +// // let mut tr = TraversalBuilder::new(Arc::clone(&storage), TraversalValue::Empty); +// // tr.v(&txn) +// // .out_e(&txn, "knows") +// // .in_v(&txn) +// // .out(&txn, "knows") +// // .filter_nodes(&txn, |val| { +// // if let Some(value) = val.check_property("name") { +// // match value { +// // Value::I32(name) => return Ok(*name < 1000), +// // _ => return Err(GraphError::Default), +// // } +// // } else { +// // return Err(GraphError::Default); +// // } +// // }) +// // .out(&txn, "knows") +// // .out(&txn, "knows") +// // .out(&txn, "knows") +// // .out(&txn, "knows") +// // .range(0, 100); + +// // let result = tr.finish(); +// // println!("original version time: {:?}", now.elapsed()); +// // println!( +// // "traversal: {:?}", +// // match result { +// // Ok(TraversalValue::NodeArray(nodes)) => nodes.len(), +// // Err(e) => { +// // println!("error: {:?}", e); +// // 0 +// // } +// // _ => { +// // println!("error: {:?}", result); +// // 0 +// // } +// // } +// // ); +// // // print size of mdb file on disk +// // println!( +// // "size of mdb file on disk: {:?}", +// // storage.graph_env.real_disk_size() +// // ); +// assert!(false); +// } + +// #[test] +// fn test_with_id_type() { +// let (storage, _temp_dir) = setup_test_db(); +// let mut txn = storage.graph_env.write_txn().unwrap(); + +// let node = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props! { "name" => "test" }), None) +// .collect_to_val(); +// txn.commit().unwrap(); +// #[derive(Serialize, Deserialize, Debug)] +// struct Input { +// id: ID, +// name: String, +// } + +// let input = sonic_rs::from_slice::( +// format!( +// "{{\"id\":\"{}\",\"name\":\"test\"}}", +// uuid::Uuid::from_u128(node.id()).to_string() +// ) +// .as_bytes(), +// ) +// .unwrap(); +// let txn = storage.graph_env.read_txn().unwrap(); +// let traversal = G::new(Arc::clone(&storage), &txn) +// .n_from_id(&input.id) +// .collect_to::>(); + +// assert_eq!(traversal.len(), 1); +// assert_eq!(traversal[0].id(), input.id.inner()); +// } + +// #[test] +// fn test_add_e_with_dup_flag() { +// let (storage, _temp_dir) = setup_test_db(); + +// let mut txn = storage.graph_env.write_txn().unwrap(); +// let mut nodes = Vec::with_capacity(1000); +// for _ in 0..1000 { +// let node1 = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_n("person", Some(props!()), None) +// .collect_to_val(); +// nodes.push(node1); +// } +// txn.commit().unwrap(); +// let random_nodes = { +// let mut n = Vec::with_capacity(10000000); +// for _ in 0..1000000 { +// let pair = ( +// &nodes[rand::rng().random_range(0..nodes.len())], +// &nodes[rand::rng().random_range(0..nodes.len())], +// ); +// n.push(pair); +// } +// n // }; -// assert_eq!(paths.len(), 1); -// let (nodes, edges) = &paths[0]; +// let now = Instant::now(); +// for chunk in random_nodes.chunks(100000) { +// let mut txn = storage.graph_env.write_txn().unwrap(); +// for (random_node1, random_node2) in chunk { +// let edge = G::new_mut(Arc::clone(&storage), &mut txn) +// .add_e( +// "knows", +// None, +// random_node1.id(), +// random_node2.id(), +// false, +// EdgeType::Node, +// ) +// .collect_to_val(); +// } +// txn.commit().unwrap(); +// } +// let end = now.elapsed(); +// println!("10 mill took {:?}", end); +// let txn = storage.graph_env.read_txn().unwrap(); +// let traversal = G::new(Arc::clone(&storage), &txn) +// .e_from_type("knows") +// .count(); +// println!("{:?}", traversal); + +// let traversal = G::new(Arc::clone(&storage), &txn) +// .n_from_type("person") +// .out_e("knows") +// .count(); +// println!("{:?}", traversal); -// assert_eq!(nodes.len(), 4); -// assert_eq!(edges.len(), 3); -// assert_eq!(nodes[0].id, users[3].id); // David -// assert_eq!(nodes[1].id, users[2].id); // Charlie -// assert_eq!(nodes[2].id, users[1].id); // Bob -// assert_eq!(nodes[3].id, users[0].id); // Alice +// assert_eq!(traversal, 10000); + +// assert!(false) // } #[test] -fn huge_traversal() { +fn test_collect_parallel() { let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - let mut nodes = Vec::with_capacity(65_000_000); - let mut start = Instant::now(); - - for i in 0..100_000 { - // nodes.push(Node::new("person", Some(props! ){ "name" => i})); - nodes.push(v6_uuid()); - } - println!("time taken to initialise nodes: {:?}", start.elapsed()); - start = Instant::now(); - - println!("time taken to sort nodes: {:?}", start.elapsed()); - start = Instant::now(); - let now = Instant::now(); - let res = G::new_mut(Arc::clone(&storage), &mut txn) - .bulk_add_n(&mut nodes, None, 1000000) - .map(|res| res.unwrap()) - .collect::>(); - txn.commit().unwrap(); - println!("time taken to add nodes: {:?}", now.elapsed()); - let start = Instant::now(); - let mut edges = Vec::with_capacity(6000 * 2000); - for i in 0..10_000 { - let random_node1 = &nodes[rand::rng().random_range(0..nodes.len())]; - let random_node2 = &nodes[rand::rng().random_range(0..nodes.len())]; - // edges.push(Edge { - // id: v6_uuid(), - // label: "knows".to_string(), - // properties: HashMap::new(), - // from_node: random_node1.id, - // to_node: random_node2.id, - // }); - edges.push((*random_node1, *random_node2, v6_uuid())); - } - println!( - "time taken to create {} edges: {:?}", - edges.len(), - start.elapsed() - ); - let mut start = Instant::now(); - let mut txn = storage.graph_env.write_txn().unwrap(); - let res = G::new_mut(Arc::clone(&storage), &mut txn) - .bulk_add_e(edges, false, 1000000) - .map(|res| res.unwrap()) - .collect::>(); - txn.commit().unwrap(); - println!("time taken to add edges: {:?}", start.elapsed()); - - let txn = storage.graph_env.read_txn().unwrap(); - let now = Instant::now(); - let traversal = G::new(Arc::clone(&storage), &txn) - .n_from_type("user") - .out_e("knows") - .to_n() - .out("knows", &EdgeType::Node) - // .filter_ref(|val, _| { - // if let Ok(TraversalVal::Node(node)) = val { - // if let Some(value) = node.check_property("name") { - // match value { - // Value::I32(name) => return *name < 700000, - // _ => return false, - // } - // } else { - // return false; - // } - // } else { - // return false; - // } - // }) - .out("knows", &EdgeType::Node) - .out("knows", &EdgeType::Node) - .out("knows", &EdgeType::Node) - .out("knows", &EdgeType::Node) - .dedup() - .range(0, 10000) - .count(); - println!("optimized version time: {:?}", now.elapsed()); - println!("traversal: {:?}", traversal); - println!( - "size of mdb file on disk: {:?}", - storage.graph_env.real_disk_size() - ); - txn.commit().unwrap(); - - // let txn = storage.graph_env.read_txn().unwrap(); - // let now = Instant::now(); - // let mut tr = TraversalBuilder::new(Arc::clone(&storage), TraversalValue::Empty); - // tr.v(&txn) - // .out_e(&txn, "knows") - // .in_v(&txn) - // .out(&txn, "knows") - // .filter_nodes(&txn, |val| { - // if let Some(value) = val.check_property("name") { - // match value { - // Value::I32(name) => return Ok(*name < 1000), - // _ => return Err(GraphError::Default), - // } - // } else { - // return Err(GraphError::Default); - // } - // }) - // .out(&txn, "knows") - // .out(&txn, "knows") - // .out(&txn, "knows") - // .out(&txn, "knows") - // .range(0, 100); - - // let result = tr.finish(); - // println!("original version time: {:?}", now.elapsed()); - // println!( - // "traversal: {:?}", - // match result { - // Ok(TraversalValue::NodeArray(nodes)) => nodes.len(), - // Err(e) => { - // println!("error: {:?}", e); - // 0 - // } - // _ => { - // println!("error: {:?}", result); - // 0 - // } - // } - // ); - // // print size of mdb file on disk - // println!( - // "size of mdb file on disk: {:?}", - // storage.graph_env.real_disk_size() - // ); - assert!(false); -} + let txn: heed3::RoTxn<'_, heed3::WithoutTls> = storage.graph_env.read_txn().unwrap(); -#[test] -fn test_with_id_type() { - let (storage, _temp_dir) = setup_test_db(); - let mut txn = storage.graph_env.write_txn().unwrap(); - - let node = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props! { "name" => "test" }), None) - .collect_to_val(); - txn.commit().unwrap(); - #[derive(Serialize, Deserialize, Debug)] - struct Input { - id: ID, - name: String, - } - - let input = sonic_rs::from_slice::( - format!( - "{{\"id\":\"{}\",\"name\":\"test\"}}", - uuid::Uuid::from_u128(node.id()).to_string() - ) - .as_bytes(), - ) - .unwrap(); - let txn = storage.graph_env.read_txn().unwrap(); - let traversal = G::new(Arc::clone(&storage), &txn) - .n_from_id(&input.id) - .collect_to::>(); - - assert_eq!(traversal.len(), 1); - assert_eq!(traversal[0].id(), input.id.inner()); -} + let res = (0..8) + .map(|_| { + G::new(Arc::clone(&storage), &txn) + .n_from_type("person") + }) + .collect::>(); -#[test] -fn test_add_e_with_dup_flag() { - let (storage, _temp_dir) = setup_test_db(); + // let traversal = traversal.map(|item| item.enumerate()); - let mut txn = storage.graph_env.write_txn().unwrap(); - let mut nodes = Vec::with_capacity(1000); - for _ in 0..1000 { - let node1 = G::new_mut(Arc::clone(&storage), &mut txn) - .add_n("person", Some(props!()), None) - .collect_to_val(); - nodes.push(node1); - } - txn.commit().unwrap(); - let random_nodes = { - let mut n = Vec::with_capacity(10000000); - for _ in 0..1000000 { - let pair = ( - &nodes[rand::rng().random_range(0..nodes.len())], - &nodes[rand::rng().random_range(0..nodes.len())], - ); - n.push(pair); - } - n - }; - - let now = Instant::now(); - for chunk in random_nodes.chunks(100000) { - let mut txn = storage.graph_env.write_txn().unwrap(); - for (random_node1, random_node2) in chunk { - let edge = G::new_mut(Arc::clone(&storage), &mut txn) - .add_e( - "knows", - None, - random_node1.id(), - random_node2.id(), - false, - EdgeType::Node, - ) - .collect_to_val(); - } - txn.commit().unwrap(); - } - let end = now.elapsed(); - println!("10 mill took {:?}", end); - let txn = storage.graph_env.read_txn().unwrap(); - let traversal = G::new(Arc::clone(&storage), &txn) - .e_from_type("knows") - .count(); - println!("{:?}", traversal); - - let traversal = G::new(Arc::clone(&storage), &txn) - .n_from_type("person") - .out_e("knows") - .count(); - println!("{:?}", traversal); - - - assert_eq!(traversal, 10000); - - assert!(false) + let result = collect_parallel(traversal); + println!("{:?}", result); } diff --git a/helixdb/src/helix_engine/storage_core/storage_core.rs b/helixdb/src/helix_engine/storage_core/storage_core.rs index df9358fa..31eb5b98 100644 --- a/helixdb/src/helix_engine/storage_core/storage_core.rs +++ b/helixdb/src/helix_engine/storage_core/storage_core.rs @@ -3,7 +3,11 @@ use crate::{ graph_core::config::Config, storage_core::storage_methods::StorageMethods, types::GraphError, - vector_core::{hnsw::HNSW, vector::HVector, vector_core::{HNSWConfig, VectorCore}}, + vector_core::{ + hnsw::HNSW, + vector::HVector, + vector_core::{HNSWConfig, VectorCore}, + }, }, protocol::{ filterable::Filterable, @@ -13,7 +17,7 @@ use crate::{ }, }; -use heed3::byteorder::BE; +use heed3::{byteorder::BE, WithoutTls}; use heed3::{types::*, Database, DatabaseFlags, Env, EnvOpenOptions, RoTxn, RwTxn, WithTls}; use std::collections::HashMap; use std::fs; @@ -30,7 +34,7 @@ const DB_IN_EDGES: &str = "in_edges"; // For incoming edge indices (i:) // Key prefixes for different types of data pub struct HelixGraphStorage { - pub graph_env: Env, + pub graph_env: Env, pub nodes_db: Database, Bytes>, pub edges_db: Database, Bytes>, pub out_edges_db: Database, @@ -52,6 +56,7 @@ impl HelixGraphStorage { // Configure and open LMDB environment let graph_env = unsafe { EnvOpenOptions::new() + .read_txn_without_tls() .map_size(db_size * 1024 * 1024 * 1024) // GB .max_dbs(20) .max_readers(200) diff --git a/helixdb/src/helix_engine/vector_core/vector_core.rs b/helixdb/src/helix_engine/vector_core/vector_core.rs index d70420c6..d3c2e437 100644 --- a/helixdb/src/helix_engine/vector_core/vector_core.rs +++ b/helixdb/src/helix_engine/vector_core/vector_core.rs @@ -5,7 +5,7 @@ use crate::helix_engine::{ use crate::protocol::value::Value; use heed3::{ types::{Bytes, Unit}, - Database, Env, RoTxn, RwTxn, + Database, Env, RoTxn, RwTxn, WithoutTls, }; use itertools::Itertools; use rand::prelude::Rng; @@ -173,7 +173,7 @@ pub struct VectorCore { } impl VectorCore { - pub fn new(env: &Env, txn: &mut RwTxn, config: HNSWConfig) -> Result { + pub fn new(env: &Env, txn: &mut RwTxn, config: HNSWConfig) -> Result { let vectors_db = env.create_database(txn, Some(DB_VECTORS))?; let vector_data_db = env.create_database(txn, Some(DB_VECTOR_DATA))?; let out_edges_db = env.create_database(txn, Some(DB_HNSW_OUT_EDGES))?;