diff --git a/Cargo.lock b/Cargo.lock index bf8c62bb8b..7ac52d5cc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4539,6 +4539,7 @@ dependencies = [ "chrono", "dashmap", "lock_api", + "num-traits", "parking_lot", "proptest", "pyo3", diff --git a/raphtory-api/Cargo.toml b/raphtory-api/Cargo.toml index 256e9cb601..51f99f0e0d 100644 --- a/raphtory-api/Cargo.toml +++ b/raphtory-api/Cargo.toml @@ -26,6 +26,7 @@ rayon = { workspace = true } rand = { workspace = true } quickcheck = { workspace = true } quickcheck_macros = { workspace = true } +num-traits = { workspace = true } twox-hash.workspace = true [dev-dependencies] diff --git a/raphtory-api/src/core/entities/mod.rs b/raphtory-api/src/core/entities/mod.rs index 02cf442c00..711e0f9565 100644 --- a/raphtory-api/src/core/entities/mod.rs +++ b/raphtory-api/src/core/entities/mod.rs @@ -1,6 +1,15 @@ +use std::borrow::Cow; + +#[cfg(feature = "python")] +use pyo3::FromPyObject; +#[cfg(feature = "python")] +use pyo3::{exceptions::PyTypeError, PyAny, PyResult}; use serde::{Deserialize, Serialize}; use self::edges::edge_ref::EdgeRef; +use num_traits::cast::ToPrimitive; + +use super::input::input_node::parse_u64_strict; pub mod edges; @@ -85,3 +94,131 @@ impl EID { EID(id as usize) } } + +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] +pub enum GID { + U64(u64), + I64(i64), + Str(String), +} + +impl Default for GID { + fn default() -> Self { + GID::U64(0) + } +} + +#[cfg(feature = "python")] +impl<'source> FromPyObject<'source> for GID { + fn extract(id: &'source PyAny) -> PyResult { + id.extract::() + .map(GID::Str) + .or_else(|_| { + id.extract::() + .map(GID::I64) + .or_else(|_| id.extract::().map(GID::U64)) + }) + .map_err(|err| { + let msg = "IDs need to be strings or an unsigned integers"; + PyTypeError::new_err(msg) + }) + } +} +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)] +pub enum GidRef<'a> { + U64(u64), + I64(i64), + Str(&'a str), +} + +impl GID { + pub fn into_str(self) -> Option { + match self { + GID::Str(v) => Some(v), + _ => None, + } + } + + pub fn into_i64(self) -> Option { + match self { + GID::I64(v) => Some(v), + _ => None, + } + } + + pub fn into_u64(self) -> Option { + match self { + GID::U64(v) => Some(v), + _ => None, + } + } + + pub fn as_str(&self) -> Option<&str> { + match self { + GID::Str(v) => Some(v.as_str()), + _ => None, + } + } + + pub fn as_i64(&self) -> Option { + match self { + GID::I64(v) => Some(*v), + _ => None, + } + } + + pub fn as_u64(&self) -> Option { + match self { + GID::U64(v) => Some(*v), + _ => None, + } + } + + pub fn to_str(&self) -> Cow { + match self { + GID::U64(v) => Cow::Owned(v.to_string()), + GID::I64(v) => Cow::Owned(v.to_string()), + GID::Str(v) => Cow::Borrowed(v), + } + } + + pub fn to_i64(&self) -> Option { + match self { + GID::U64(v) => v.to_i64(), + GID::I64(v) => Some(*v), + GID::Str(v) => parse_u64_strict(v)?.to_i64(), + } + } + + pub fn to_u64(&self) -> Option { + match self { + GID::U64(v) => Some(*v), + GID::I64(v) => v.to_u64(), + GID::Str(v) => parse_u64_strict(v), + } + } +} + +impl From for GID { + fn from(id: u64) -> Self { + Self::U64(id) + } +} + +impl From for GID { + fn from(id: i64) -> Self { + Self::I64(id) + } +} + +impl From for GID { + fn from(id: String) -> Self { + Self::Str(id) + } +} + +impl From<&str> for GID { + fn from(id: &str) -> Self { + Self::Str(id.to_string()) + } +} diff --git a/raphtory/src/algorithms/community_detection/label_propagation.rs b/raphtory/src/algorithms/community_detection/label_propagation.rs index d9e092b170..308b41d712 100644 --- a/raphtory/src/algorithms/community_detection/label_propagation.rs +++ b/raphtory/src/algorithms/community_detection/label_propagation.rs @@ -24,13 +24,15 @@ pub fn label_propagation( where G: StaticGraphViewOps, { - let mut labels: HashMap, u64> = HashMap::new(); - for node in graph.nodes() { - labels.insert(node.clone(), node.id()); + let mut labels: HashMap, u64> = HashMap::new(); + let nodes = graph.nodes(); + for node in nodes.iter() { + let id = node.id(); + labels.insert(node, id); } let nodes = graph.nodes(); - let mut shuffled_nodes: Vec> = nodes.iter().collect(); + let mut shuffled_nodes: Vec> = nodes.iter().collect(); if let Some(seed_value) = seed { let mut rng = StdRng::from_seed(seed_value); shuffled_nodes.shuffle(&mut rng); @@ -46,12 +48,12 @@ where let mut label_count: BTreeMap = BTreeMap::new(); for neighbour in neighbors { - *label_count.entry(labels[&neighbour.clone()]).or_insert(0.0) += 1.0; + *label_count.entry(labels[&neighbour]).or_insert(0.0) += 1.0; } if let Some(max_label) = find_max_label(&label_count) { if max_label != labels[node] { - labels.insert(node.clone(), max_label); + labels.insert(*node, max_label); changed = true; } } @@ -61,7 +63,7 @@ where // Group nodes by their labels to form communities let mut communities: HashMap>> = HashMap::new(); for (node, label) in labels { - communities.entry(label).or_default().insert(node.clone()); + communities.entry(label).or_default().insert(node.cloned()); } Ok(communities.values().cloned().collect()) diff --git a/raphtory/src/algorithms/community_detection/modularity.rs b/raphtory/src/algorithms/community_detection/modularity.rs index 0635874463..c20d027d46 100644 --- a/raphtory/src/algorithms/community_detection/modularity.rs +++ b/raphtory/src/algorithms/community_detection/modularity.rs @@ -184,14 +184,10 @@ impl ModularityFunction for ModularityUnDir { tol: f64, ) -> Self { let _n = graph.count_nodes(); - let local_id_map: HashMap<_, _> = graph - .nodes() - .iter() - .enumerate() - .map(|(i, n)| (n, VID(i))) - .collect(); - let adj: Vec<_> = graph - .nodes() + let nodes = graph.nodes(); + let local_id_map: HashMap<_, _> = + nodes.iter().enumerate().map(|(i, n)| (n, VID(i))).collect(); + let adj: Vec<_> = nodes .iter() .map(|node| { node.edges() diff --git a/raphtory/src/algorithms/components/connected_components.rs b/raphtory/src/algorithms/components/connected_components.rs index c4e469c8aa..f4321e279b 100644 --- a/raphtory/src/algorithms/components/connected_components.rs +++ b/raphtory/src/algorithms/components/connected_components.rs @@ -43,7 +43,7 @@ where let min_neighbour_id = vv.neighbours().id().min(); let id = vv.id(); let state: &mut WccState = vv.get_mut(); - state.component = cmp::min(min_neighbour_id.unwrap_or(id), id); + state.component = min_neighbour_id.unwrap_or(id).min(id); Step::Continue }); diff --git a/raphtory/src/algorithms/layout/cohesive_fruchterman_reingold.rs b/raphtory/src/algorithms/layout/cohesive_fruchterman_reingold.rs index a1d384ef3c..10fd70d771 100644 --- a/raphtory/src/algorithms/layout/cohesive_fruchterman_reingold.rs +++ b/raphtory/src/algorithms/layout/cohesive_fruchterman_reingold.rs @@ -44,8 +44,8 @@ pub fn cohesive_fruchterman_reingold<'graph, G: GraphViewOps<'graph>>( .max() .unwrap_or(0); // Default to 0 if there are no nodes - let nodes_with_max_degree: Vec<_> = virtual_graph - .nodes() + let nodes = &virtual_graph.nodes(); + let nodes_with_max_degree: Vec<_> = nodes .iter() .filter(|node| node.degree() == max_degree) .collect(); diff --git a/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs b/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs index 78551c460d..c4f436832d 100644 --- a/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs +++ b/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs @@ -22,8 +22,8 @@ pub fn temporal_bipartite_projection( pivot_type: String, ) -> Graph { let new_graph = Graph::new(); - let nodes = graph - .nodes() + let nodes = graph.nodes(); + let nodes = nodes .iter() .filter(|v| v.node_type().unwrap() == pivot_type); for v in nodes { diff --git a/raphtory/src/core/entities/graph/mod.rs b/raphtory/src/core/entities/graph/mod.rs index 8fabb32ac4..a85f876292 100644 --- a/raphtory/src/core/entities/graph/mod.rs +++ b/raphtory/src/core/entities/graph/mod.rs @@ -5,10 +5,7 @@ pub(crate) mod timer; #[cfg(test)] mod test { use crate::{ - core::{ - entities::{graph::tgraph::TemporalGraph, LayerIds}, - Direction, PropType, - }, + core::PropType, db::api::{mutation::internal::InternalAdditionOps, storage::storage_ops::GraphStorage}, prelude::*, }; @@ -19,8 +16,8 @@ mod test { let l_btc = g.resolve_layer(Some("btc")); let l_eth = g.resolve_layer(Some("eth")); let l_tether = g.resolve_layer(Some("tether")); - let v1 = g.resolve_node(1, None); - let v2 = g.resolve_node(2, None); + let v1 = g.resolve_node(1).unwrap(); + let v2 = g.resolve_node(2).unwrap(); let tx_sent_id = g .resolve_edge_property("tx_sent", PropType::I32, false) .unwrap(); @@ -74,7 +71,7 @@ mod test { let ns = v .neighbours() .into_iter() - .map(|n| n.id()) + .filter_map(|n| n.id().as_u64()) .collect::>(); assert_eq!(ns, [v2, v3]); } diff --git a/raphtory/src/core/entities/graph/tgraph.rs b/raphtory/src/core/entities/graph/tgraph.rs index 5f41b137c7..cf1745ea87 100644 --- a/raphtory/src/core/entities/graph/tgraph.rs +++ b/raphtory/src/core/entities/graph/tgraph.rs @@ -6,9 +6,12 @@ use crate::{ tgraph_storage::GraphStorage, timer::{MaxCounter, MinCounter, TimeCounterTrait}, }, - nodes::{node_ref::NodeRef, node_store::NodeStore}, + nodes::{ + node_ref::{AsNodeRef, NodeRef}, + node_store::NodeStore, + }, properties::{graph_meta::GraphMeta, props::Meta}, - LayerIds, EID, VID, + LayerIds, EID, VID, GID }, storage::{ raw_edges::EdgeWGuard, @@ -21,6 +24,7 @@ use crate::{ db::api::view::Layer, }; use dashmap::DashSet; +use either::Either; use itertools::Itertools; use raphtory_api::core::{ entities::edges::edge_ref::EdgeRef, @@ -42,7 +46,7 @@ pub(crate) type FxDashSet = DashSet>; #[derive(Serialize, Deserialize, Debug)] pub struct TemporalGraph { // mapping between logical and physical ids - logical_to_physical: FxDashMap, + logical_to_physical: FxDashMap, string_pool: FxDashSet, pub(crate) storage: GraphStorage, @@ -110,25 +114,6 @@ impl TemporalGraph { self.edge_meta.layer_meta().len() } - // pub(crate) fn layer_names(&self, layer_ids: &LayerIds) -> BoxedIter { - // let layer_ids = layer_ids.clone(); - // match layer_ids { - // LayerIds::None => Box::new(iter::empty()), - // LayerIds::All => Box::new(self.edge_meta.layer_meta().get_keys().into_iter()), - // LayerIds::One(id) => { - // let name = self.edge_meta.layer_meta().get_name(id).clone(); - // Box::new(iter::once(name)) - // } - // LayerIds::Multiple(ids) => { - // let keys = self.edge_meta.layer_meta().get_keys(); - // Box::new((0..ids.len()).map(move |index| { - // let id = ids[index]; - // keys[id].clone() - // })) - // } - // } - // } - pub(crate) fn layer_ids(&self, key: Layer) -> Result { match key { Layer::None => Ok(LayerIds::None), @@ -213,33 +198,6 @@ impl TemporalGraph { Some(self.latest_time.get()).filter(|t| *t != i64::MIN) } - // #[inline] - // pub(crate) fn global_node_id(&self, v: VID) -> u64 { - // let node = self.storage.get_node(v); - // node.global_id() - // } - - // pub(crate) fn node_name(&self, v: VID) -> String { - // let node = self.storage.get_node(v); - // node.name - // .clone() - // .unwrap_or_else(|| node.global_id().to_string()) - // } - - // pub(crate) fn node_type(&self, v: VID) -> Option { - // let node = self.storage.get_node(v); - // self.node_meta.get_node_type_name_by_id(node.node_type) - // } - - // pub(crate) fn node_type_id(&self, v: VID) -> usize { - // let node = self.storage.get_node(v); - // node.node_type - // } - - // pub(crate) fn get_all_node_types(&self) -> Vec { - // self.node_meta.get_all_node_types() - // } - pub(crate) fn core_temporal_edge_prop_ids( &self, e: EdgeRef, @@ -357,12 +315,17 @@ impl TemporalGraph { } /// return local id for node, initialising storage if node does not exist yet - pub(crate) fn resolve_node(&self, id: u64, name: Option<&str>) -> VID { - *(self.logical_to_physical.entry(id).or_insert_with(|| { - let name = name.map(|s| s.to_owned()); - let node_store = NodeStore::empty(id, name); - self.storage.push_node(node_store) - })) + pub(crate) fn resolve_node(&self, n: V) -> VID { + match n.into_gid() { + Either::Left(id) => { + let name = id.as_str().map(|s| s.to_string()); + *(self.logical_to_physical.entry(id.clone()).or_insert_with(|| { + let node_store = NodeStore::empty(id, name); + self.storage.push_node(node_store) + })) + } + Either::Right(vid) => vid, + } } pub(crate) fn resolve_node_type( @@ -536,10 +499,13 @@ impl TemporalGraph { match v { NodeRef::Internal(vid) => Some(vid), NodeRef::External(gid) => { - let v_id = self.logical_to_physical.get(&gid)?; + let v_id = self.logical_to_physical.get(&GID::U64(gid))?; + Some(*v_id) + } + NodeRef::ExternalStr(string) => { + let v_id = self.logical_to_physical.get(&GID::Str(string.to_owned()))?; Some(*v_id) } - NodeRef::ExternalStr(string) => self.resolve_node_ref(NodeRef::External(string.id())), } } diff --git a/raphtory/src/core/entities/nodes/node_ref.rs b/raphtory/src/core/entities/nodes/node_ref.rs index 7a3888be7f..6e130b6587 100644 --- a/raphtory/src/core/entities/nodes/node_ref.rs +++ b/raphtory/src/core/entities/nodes/node_ref.rs @@ -1,4 +1,6 @@ use crate::core::entities::VID; +use either::Either; +use raphtory_api::core::entities::GID; #[derive(Copy, Clone, PartialOrd, PartialEq, Debug)] pub enum NodeRef<'a> { @@ -9,6 +11,14 @@ pub enum NodeRef<'a> { pub trait AsNodeRef { fn as_node_ref(&self) -> NodeRef; + + fn into_gid(self) -> Either where Self: Sized { + match self.as_node_ref() { + NodeRef::Internal(vid) => Either::Right(vid), + NodeRef::External(u) => Either::Left(GID::U64(u)), + NodeRef::ExternalStr(s) => Either::Left(GID::Str(s.to_string())), + } + } } impl<'a> AsNodeRef for NodeRef<'a> { @@ -47,6 +57,16 @@ impl<'a, V: AsNodeRef> AsNodeRef for &'a V { } } +impl AsNodeRef for GID { + fn as_node_ref(&self) -> NodeRef { + match self { + GID::U64(u) => NodeRef::External(*u), + GID::Str(s) => NodeRef::ExternalStr(s), + GID::I64(i) => NodeRef::External(*i as u64), + } + } +} + impl<'a> NodeRef<'a> { /// Makes a new node reference from an internal `VID`. /// Values are unchecked and the node is assumed to exist so use with caution! diff --git a/raphtory/src/core/entities/nodes/node_store.rs b/raphtory/src/core/entities/nodes/node_store.rs index b7e365de49..e91ce9b581 100644 --- a/raphtory/src/core/entities/nodes/node_store.rs +++ b/raphtory/src/core/entities/nodes/node_store.rs @@ -3,7 +3,7 @@ use crate::core::{ edges::edge_ref::{Dir, EdgeRef}, nodes::structure::adj::Adj, properties::{props::Props, tprop::TProp}, - LayerIds, EID, VID, + LayerIds, EID, VID, GID }, storage::{ lazy_vec::IllegalSet, @@ -22,7 +22,7 @@ use std::{ #[derive(Serialize, Deserialize, Debug, Default, PartialEq)] pub struct NodeStore { - pub(crate) global_id: u64, + pub(crate) global_id: GID, pub(crate) name: Option, pub(crate) vid: VID, // all the timestamps that have been seen by this node @@ -35,7 +35,7 @@ pub struct NodeStore { } impl NodeStore { - pub fn new(global_id: u64, t: TimeIndexEntry) -> Self { + pub fn new(global_id: GID, t: TimeIndexEntry) -> Self { let mut layers = Vec::with_capacity(1); layers.push(Adj::Solo); Self { @@ -49,7 +49,7 @@ impl NodeStore { } } - pub fn empty(global_id: u64, name: Option) -> Self { + pub fn empty(global_id: GID, name: Option) -> Self { let mut layers = Vec::with_capacity(1); layers.push(Adj::Solo); Self { @@ -63,8 +63,8 @@ impl NodeStore { } } - pub fn global_id(&self) -> u64 { - self.global_id + pub fn global_id(&self) -> &GID { + &self.global_id } pub fn timestamps(&self) -> &TimeIndex { diff --git a/raphtory/src/db/api/mutation/addition_ops.rs b/raphtory/src/db/api/mutation/addition_ops.rs index 1bb5ae0a8f..7b8b7ee697 100644 --- a/raphtory/src/db/api/mutation/addition_ops.rs +++ b/raphtory/src/db/api/mutation/addition_ops.rs @@ -1,6 +1,6 @@ use crate::{ core::{ - entities::edges::edge_ref::EdgeRef, + entities::{edges::edge_ref::EdgeRef, nodes::node_ref::AsNodeRef}, utils::{errors::GraphError, time::IntoTimeWithFormat}, Prop, }, @@ -39,7 +39,7 @@ pub trait AdditionOps: StaticGraphViewOps { /// let v = g.add_node(0, "Alice", NO_PROPS, None); /// let v = g.add_node(0, 5, NO_PROPS, None); /// ``` - fn add_node( + fn add_node( &self, t: T, v: V, @@ -47,7 +47,7 @@ pub trait AdditionOps: StaticGraphViewOps { node_type: Option<&str>, ) -> Result, GraphError>; - fn add_node_with_custom_time_format( + fn add_node_with_custom_time_format( &self, t: &str, fmt: &str, @@ -79,7 +79,7 @@ pub trait AdditionOps: StaticGraphViewOps { /// graph.add_node(2, "Bob", NO_PROPS, None).unwrap(); /// graph.add_edge(3, "Alice", "Bob", NO_PROPS, None).unwrap(); /// ``` - fn add_edge( + fn add_edge( &self, t: T, src: V, @@ -88,7 +88,7 @@ pub trait AdditionOps: StaticGraphViewOps { layer: Option<&str>, ) -> Result, GraphError>; - fn add_edge_with_custom_time_format( + fn add_edge_with_custom_time_format( &self, t: &str, fmt: &str, @@ -103,7 +103,7 @@ pub trait AdditionOps: StaticGraphViewOps { } impl AdditionOps for G { - fn add_node( + fn add_node( &self, t: T, v: V, @@ -115,13 +115,13 @@ impl AdditionOps for G { |prop| self.process_prop_value(prop), )?; let ti = time_from_input(self, t)?; - let v_id = self.resolve_node(v.id(), v.id_str()); + let v_id = self.resolve_node(v)?; let type_id = self.resolve_node_type(v_id, node_type)?; self.internal_add_node(ti, v_id, properties, type_id)?; Ok(NodeView::new_internal(self.clone(), v_id)) } - fn add_edge( + fn add_edge( &self, t: T, src: V, @@ -130,8 +130,8 @@ impl AdditionOps for G { layer: Option<&str>, ) -> Result, GraphError> { let ti = time_from_input(self, t)?; - let src_id = self.resolve_node(src.id(), src.id_str()); - let dst_id = self.resolve_node(dst.id(), dst.id_str()); + let src_id = self.resolve_node(src)?; + let dst_id = self.resolve_node(dst)?; let layer_id = self.resolve_layer(layer); let properties: Vec<(usize, Prop)> = props.collect_properties( diff --git a/raphtory/src/db/api/mutation/deletion_ops.rs b/raphtory/src/db/api/mutation/deletion_ops.rs index 888db66bd3..b6131cf726 100644 --- a/raphtory/src/db/api/mutation/deletion_ops.rs +++ b/raphtory/src/db/api/mutation/deletion_ops.rs @@ -1,5 +1,5 @@ use crate::{ - core::utils::{errors::GraphError, time::IntoTimeWithFormat}, + core::{entities::nodes::node_ref::AsNodeRef, utils::{errors::GraphError, time::IntoTimeWithFormat}}, db::api::mutation::{ internal::{InternalAdditionOps, InternalDeletionOps}, TryIntoInputTime, @@ -10,7 +10,7 @@ use raphtory_api::core::input::input_node::InputNode; use super::time_from_input; pub trait DeletionOps: InternalDeletionOps + InternalAdditionOps + Sized { - fn delete_edge( + fn delete_edge( &self, t: T, src: V, @@ -18,13 +18,13 @@ pub trait DeletionOps: InternalDeletionOps + InternalAdditionOps + Sized { layer: Option<&str>, ) -> Result<(), GraphError> { let ti = time_from_input(self, t)?; - let src_id = self.resolve_node(src.id(), src.id_str()); - let dst_id = self.resolve_node(dst.id(), src.id_str()); + let src_id = self.resolve_node(src)?; + let dst_id = self.resolve_node(dst)?; let layer = self.resolve_layer(layer); self.internal_delete_edge(ti, src_id, dst_id, layer) } - fn delete_edge_with_custom_time_format( + fn delete_edge_with_custom_time_format( &self, t: &str, fmt: &str, diff --git a/raphtory/src/db/api/mutation/internal/internal_addition_ops.rs b/raphtory/src/db/api/mutation/internal/internal_addition_ops.rs index eb0b808612..90fe4a6cba 100644 --- a/raphtory/src/db/api/mutation/internal/internal_addition_ops.rs +++ b/raphtory/src/db/api/mutation/internal/internal_addition_ops.rs @@ -1,6 +1,6 @@ use crate::{ core::{ - entities::{EID, VID}, + entities::{nodes::node_ref::AsNodeRef, EID, VID}, storage::timeindex::TimeIndexEntry, utils::errors::GraphError, Prop, PropType, @@ -20,7 +20,7 @@ pub trait InternalAdditionOps { fn resolve_node_type(&self, v_id: VID, node_type: Option<&str>) -> Result; /// map external node id to internal id, allocating a new empty node if needed - fn resolve_node(&self, id: u64, name: Option<&str>) -> VID; + fn resolve_node(&self, id: V) -> Result; /// map property key to internal id, allocating new property if needed fn resolve_graph_property(&self, prop: &str, is_static: bool) -> usize; @@ -98,8 +98,8 @@ impl InternalAdditionOps for G { } #[inline] - fn resolve_node(&self, id: u64, name: Option<&str>) -> VID { - self.graph().resolve_node(id, name) + fn resolve_node(&self, n: V) -> Result { + self.graph().resolve_node(n) } #[inline] diff --git a/raphtory/src/db/api/storage/locked.rs b/raphtory/src/db/api/storage/locked.rs index a1875983b2..9341f2e242 100644 --- a/raphtory/src/db/api/storage/locked.rs +++ b/raphtory/src/db/api/storage/locked.rs @@ -12,6 +12,24 @@ pub struct LockedGraph { pub(crate) graph: Arc, } +impl <'de> serde::Deserialize<'de> for LockedGraph { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + TemporalGraph::deserialize(deserializer).map(|graph| LockedGraph::new(Arc::new(graph))) + } +} + +impl serde::Serialize for LockedGraph { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.graph.serialize(serializer) + } +} + impl LockedGraph { pub fn new(graph: Arc) -> Self { let nodes = Arc::new(graph.storage.nodes_read_lock()); diff --git a/raphtory/src/db/api/storage/nodes/node_entry.rs b/raphtory/src/db/api/storage/nodes/node_entry.rs index 399b833d3a..710989cd89 100644 --- a/raphtory/src/db/api/storage/nodes/node_entry.rs +++ b/raphtory/src/db/api/storage/nodes/node_entry.rs @@ -1,5 +1,7 @@ use std::borrow::Cow; +use raphtory_api::core::entities::GID; + #[cfg(feature = "storage")] use crate::disk_graph::storage_interface::node::DiskNode; use crate::{ @@ -132,7 +134,7 @@ impl<'a, 'b: 'a> NodeStorageOps<'a> for &'a NodeStorageEntry<'b> { self.as_ref().vid() } - fn id(self) -> u64 { + fn id(self) -> GID { self.as_ref().id() } diff --git a/raphtory/src/db/api/storage/nodes/node_ref.rs b/raphtory/src/db/api/storage/nodes/node_ref.rs index 763afc9cec..cbd531ddbb 100644 --- a/raphtory/src/db/api/storage/nodes/node_ref.rs +++ b/raphtory/src/db/api/storage/nodes/node_ref.rs @@ -1,5 +1,7 @@ use std::borrow::Cow; +use raphtory_api::core::entities::GID; + #[cfg(feature = "storage")] use crate::db::api::storage::variants::storage_variants::StorageVariants; @@ -95,7 +97,7 @@ impl<'a> NodeStorageOps<'a> for NodeStorageRef<'a> { for_all!(self, node => node.vid()) } - fn id(self) -> u64 { + fn id(self) -> GID { for_all!(self, node => node.id()) } diff --git a/raphtory/src/db/api/storage/nodes/node_storage_ops.rs b/raphtory/src/db/api/storage/nodes/node_storage_ops.rs index 6bfc1c1a6f..ecc2d852f4 100644 --- a/raphtory/src/db/api/storage/nodes/node_storage_ops.rs +++ b/raphtory/src/db/api/storage/nodes/node_storage_ops.rs @@ -13,7 +13,7 @@ use crate::{ prelude::Prop, }; use itertools::Itertools; -use raphtory_api::core::storage::arc_str::OptionAsStr; +use raphtory_api::core::{entities::GID, storage::arc_str::OptionAsStr}; pub trait NodeStorageOps<'a>: Sized { fn degree(self, layers: &LayerIds, dir: Direction) -> usize; @@ -31,7 +31,7 @@ pub trait NodeStorageOps<'a>: Sized { fn vid(self) -> VID; - fn id(self) -> u64; + fn id(self) -> GID; fn name(self) -> Option>; @@ -71,8 +71,8 @@ impl<'a> NodeStorageOps<'a> for &'a NodeStore { self.vid } - fn id(self) -> u64 { - self.global_id + fn id(self) -> GID { + self.global_id.clone() } fn name(self) -> Option> { diff --git a/raphtory/src/db/api/storage/storage_ops/additions.rs b/raphtory/src/db/api/storage/storage_ops/additions.rs index a968263d85..c27262de51 100644 --- a/raphtory/src/db/api/storage/storage_ops/additions.rs +++ b/raphtory/src/db/api/storage/storage_ops/additions.rs @@ -6,7 +6,7 @@ use raphtory_api::core::{ }; use crate::{ - core::{utils::errors::GraphError, PropType}, + core::{entities::nodes::node_ref::AsNodeRef, utils::errors::GraphError, PropType}, db::api::mutation::internal::InternalAdditionOps, prelude::Prop, }; @@ -36,14 +36,14 @@ impl InternalAdditionOps for GraphStorage { fn resolve_node_type(&self, v_id: VID, node_type: Option<&str>) -> Result { match self { GraphStorage::Unlocked(storage) => storage.resolve_node_type(v_id, node_type), - _ => todo!(), + _ => Err(GraphError::AttemptToMutateImmutableGraph), } } - fn resolve_node(&self, id: u64, name: Option<&str>) -> VID { + fn resolve_node(&self, n: V) -> Result { match self { - GraphStorage::Unlocked(storage) => storage.resolve_node(id, name), - _ => todo!(), + GraphStorage::Unlocked(storage) => Ok(storage.resolve_node(n)), + _ => Err(GraphError::AttemptToMutateImmutableGraph), } } diff --git a/raphtory/src/db/api/storage/storage_ops/mod.rs b/raphtory/src/db/api/storage/storage_ops/mod.rs index bf92c460b2..1c176062ee 100644 --- a/raphtory/src/db/api/storage/storage_ops/mod.rs +++ b/raphtory/src/db/api/storage/storage_ops/mod.rs @@ -36,6 +36,7 @@ use itertools::Itertools; use pometry_storage::GID; use raphtory_api::core::entities::ELID; use rayon::prelude::*; +use serde::{Deserialize, Serialize}; use std::{iter, sync::Arc}; #[cfg(feature = "storage")] @@ -69,7 +70,7 @@ pub mod prop_add; pub mod time_props; pub mod time_semantics; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum GraphStorage { Mem(LockedGraph), Unlocked(Arc), diff --git a/raphtory/src/db/api/view/edge.rs b/raphtory/src/db/api/view/edge.rs index d7ce9e6eb1..c0a0b2d8ac 100644 --- a/raphtory/src/db/api/view/edge.rs +++ b/raphtory/src/db/api/view/edge.rs @@ -1,7 +1,7 @@ use std::iter; use chrono::{DateTime, Utc}; -use raphtory_api::core::storage::arc_str::ArcStr; +use raphtory_api::core::{entities::GID, storage::arc_str::ArcStr}; use crate::{ core::{ @@ -99,7 +99,7 @@ pub trait EdgeViewOps<'graph>: TimeOps<'graph> + LayerOps<'graph> + Clone { fn active(&self, t: i64) -> Self::ValueType; /// Returns the id of the edge. - fn id(&self) -> Self::ValueType<(u64, u64)>; + fn id(&self) -> Self::ValueType<(GID, GID)>; /// Explodes an edge and returns all instances it had been updated as seperate edges fn explode(&self) -> Self::Exploded; @@ -214,7 +214,7 @@ impl<'graph, E: BaseEdgeViewOps<'graph>> EdgeViewOps<'graph> for E { }) } - fn id(&self) -> Self::ValueType<(u64, u64)> { + fn id(&self) -> Self::ValueType<(GID, GID)> { self.map(|g, e| (g.node_id(e.src()), g.node_id(e.dst()))) } @@ -437,12 +437,12 @@ mod test_edge_view { let res: Vec<_> = exploded_edges .into_iter() - .map(|e| { - ( - e.src().id(), - e.dst().id(), + .filter_map(|e| { + Some(( + e.src().id().as_u64()?, + e.dst().id().as_u64()?, e.properties().get("second").into_bool(), - ) + )) }) .collect(); assert_eq!( diff --git a/raphtory/src/db/api/view/internal/core_ops.rs b/raphtory/src/db/api/view/internal/core_ops.rs index c3e9eead75..ec1b9a4cab 100644 --- a/raphtory/src/db/api/view/internal/core_ops.rs +++ b/raphtory/src/db/api/view/internal/core_ops.rs @@ -31,7 +31,7 @@ use std::{iter, ops::Range}; #[cfg(feature = "storage")] use pometry_storage::timestamps::TimeStamps; -use raphtory_api::core::storage::arc_str::ArcStr; +use raphtory_api::core::{entities::GID, storage::arc_str::ArcStr}; #[cfg(feature = "storage")] use rayon::prelude::*; @@ -121,7 +121,7 @@ pub trait CoreGraphOps { } /// Returns the external ID for a node - fn node_id(&self, v: VID) -> u64 { + fn node_id(&self, v: VID) -> GID { self.core_graph().node_entry(v).id() } diff --git a/raphtory/src/db/api/view/internal/materialize.rs b/raphtory/src/db/api/view/internal/materialize.rs index f350508122..d83d427f66 100644 --- a/raphtory/src/db/api/view/internal/materialize.rs +++ b/raphtory/src/db/api/view/internal/materialize.rs @@ -2,7 +2,7 @@ use crate::{ core::{ entities::{ edges::edge_ref::EdgeRef, - nodes::node_ref::NodeRef, + nodes::node_ref::{NodeRef, AsNodeRef}, properties::{graph_meta::GraphMeta, props::Meta, tprop::TProp}, LayerIds, EID, ELID, VID, }, @@ -172,6 +172,8 @@ where #[cfg(test)] mod test_materialised_graph_dispatch { + use raphtory_api::core::entities::GID; + use crate::{ core::entities::LayerIds, db::api::view::internal::{ @@ -224,6 +226,6 @@ mod test_materialised_graph_dispatch { let mg = g.materialize().unwrap(); let v = mg.add_node(0, 1, NO_PROPS, None).unwrap(); - assert_eq!(v.id(), 1) + assert_eq!(v.id(), GID::U64(1)) } } diff --git a/raphtory/src/db/api/view/internal/mod.rs b/raphtory/src/db/api/view/internal/mod.rs index bdc3b750b5..05aad0ee90 100644 --- a/raphtory/src/db/api/view/internal/mod.rs +++ b/raphtory/src/db/api/view/internal/mod.rs @@ -158,8 +158,8 @@ mod test { fn test_boxing() { // this tests that a boxed graph actually compiles let g = Graph::new(); - g.add_node(0, 1, NO_PROPS, None).unwrap(); + g.add_node(0, 1u64, NO_PROPS, None).unwrap(); let boxed: Arc = Arc::new(g); - assert_eq!(boxed.nodes().id().values().collect_vec(), vec![1]) + assert_eq!(boxed.nodes().id().values().filter_map(|v| v.as_u64()).collect_vec(), vec![1]) } } diff --git a/raphtory/src/db/api/view/node.rs b/raphtory/src/db/api/view/node.rs index ab857340b8..8fb0866cf0 100644 --- a/raphtory/src/db/api/view/node.rs +++ b/raphtory/src/db/api/view/node.rs @@ -16,7 +16,7 @@ use crate::{ prelude::{EdgeViewOps, GraphViewOps, LayerOps}, }; use chrono::{DateTime, Utc}; -use raphtory_api::core::storage::arc_str::ArcStr; +use raphtory_api::core::{entities::GID, storage::arc_str::ArcStr}; pub trait BaseNodeViewOps<'graph>: Clone + TimeOps<'graph> + LayerOps<'graph> { type BaseGraph: GraphViewOps<'graph>; @@ -70,7 +70,7 @@ pub trait NodeViewOps<'graph>: Clone + TimeOps<'graph> + LayerOps<'graph> { type Edges: EdgeViewOps<'graph, Graph = Self::Graph, BaseGraph = Self::BaseGraph> + 'graph; /// Get the numeric id of the node - fn id(&self) -> Self::ValueType; + fn id(&self) -> Self::ValueType; /// Get the name of this node if a user has set one otherwise it returns the ID. /// @@ -178,7 +178,7 @@ impl<'graph, V: BaseNodeViewOps<'graph> + 'graph> NodeViewOps<'graph> for V { type Edges = V::Edges; #[inline] - fn id(&self) -> Self::ValueType { + fn id(&self) -> Self::ValueType { self.map(|cg, _g, v| cg.node_entry(v).id()) } #[inline] diff --git a/raphtory/src/db/api/view/serialise.rs b/raphtory/src/db/api/view/serialise.rs index 4e7b19b035..2bad9a65e4 100644 --- a/raphtory/src/db/api/view/serialise.rs +++ b/raphtory/src/db/api/view/serialise.rs @@ -396,7 +396,7 @@ impl< // align the nodes for node in g.nodes { - let l_vid = graph.resolve_node(node.gid, node.name.as_deref()); + let l_vid = graph.resolve_node(node.gid)?; assert_eq!(l_vid, VID(node.vid as usize)); } diff --git a/raphtory/src/db/graph/graph.rs b/raphtory/src/db/graph/graph.rs index 171e970f3d..0f7ff0cba0 100644 --- a/raphtory/src/db/graph/graph.rs +++ b/raphtory/src/db/graph/graph.rs @@ -39,30 +39,9 @@ use super::views::deletion_graph::PersistentGraph; #[repr(transparent)] #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Graph { - #[serde( - deserialize_with = "deserialise_storage", - serialize_with = "serialise_storage" - )] inner: GraphStorage, } -fn deserialise_storage<'de, D>(deserializer: D) -> Result -where - D: serde::Deserializer<'de>, -{ - TemporalGraph::deserialize(deserializer).map(|tg| GraphStorage::Unlocked(Arc::new(tg))) -} - -fn serialise_storage(storage: &GraphStorage, serializer: S) -> Result -where - S: serde::Serializer, -{ - match storage { - GraphStorage::Unlocked(storage) => storage.serialize(serializer), - _ => panic!("Cannot serialise locked storage"), // TODO: fix this at some point - } -} - impl Static for Graph {} pub fn graph_equal<'graph1, 'graph2, G1: GraphViewOps<'graph1>, G2: GraphViewOps<'graph2>>( @@ -114,7 +93,7 @@ pub fn assert_graph_equal< g2.count_temporal_edges() ); for n1 in g1.nodes() { - assert!(g2.has_node(n1.id()), "missing node {}", n1.id()); + assert!(g2.has_node(n1.id()), "missing node {:?}", n1.id()); let c1 = n1.properties().constant().into_iter().count(); let t1 = n1.properties().temporal().into_iter().count(); @@ -645,8 +624,8 @@ mod db_tests { .unwrap() .edge(1, 3) .unwrap(); - assert_eq!(e.src().id(), 1u64); - assert_eq!(e.dst().id(), 3u64); + assert_eq!(e.src().id().into_u64(), Some(1u64)); + assert_eq!(e.dst().id().into_u64(), Some(3u64)); }); } @@ -996,9 +975,9 @@ mod db_tests { .map(|i| { let v = graph.node(i).unwrap(); ( - v.window(-1, 7).in_neighbours().id().collect::>(), - v.window(1, 7).out_neighbours().id().collect::>(), - v.window(0, 1).neighbours().id().collect::>(), + v.window(-1, 7).in_neighbours().id().filter_map(|id| id.as_u64()).collect::>(), + v.window(1, 7).out_neighbours().id().filter_map(|id| id.as_u64()).collect::>(), + v.window(0, 1).neighbours().id().filter_map(|id| id.as_u64()).collect::>(), ) }) .collect::>(); @@ -1139,7 +1118,7 @@ mod db_tests { fn to_ids<'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'graph>>( neighbours: PathFromNode<'graph, G, GH>, ) -> Vec { - neighbours.iter().map(|n| n.id()).sorted().collect_vec() + neighbours.iter().filter_map(|n| n.id().as_u64()).sorted().collect_vec() } assert_eq!(to_ids(node.neighbours()), vec![22, 33, 44]); @@ -1745,10 +1724,10 @@ mod db_tests { // FIXME: Node add without properties not showing up (Issue #46) test_graph(&graph, |graph| { - assert_eq!(graph.nodes().id().collect::>(), vec![1, 2, 3]); + assert_eq!(graph.nodes().id().collect::>(), vec![1u64.into(), 2u64.into(), 3u64.into()]); let g_at = graph.at(1); - assert_eq!(g_at.nodes().id().collect::>(), vec![1, 2]); + assert_eq!(g_at.nodes().id().collect::>(), vec![1u64.into(), 2u64.into()]); }); } @@ -1761,7 +1740,7 @@ mod db_tests { // FIXME: Needs multilayer support (Issue #47) test_graph(&graph, |graph| { let what = graph.edges().id().collect_vec(); - assert_eq!(what, vec![(0, 1)]); + assert_eq!(what, vec![(0u64.into(), 1u64.into())]); let layer_names = graph.edges().layer_names().flatten().sorted().collect_vec(); assert_eq!(layer_names, vec!["_default", "awesome name"]); @@ -1805,7 +1784,7 @@ mod db_tests { assert!(g_layers.edge(1, 4).is_none()); let one = g_layers.node(1).expect("node"); - let ns = one.neighbours().iter().map(|v| v.id()).collect::>(); + let ns = one.neighbours().iter().filter_map(|v| v.id().as_u64()).collect::>(); assert_eq!(ns, vec![2, 3]); let g_layers2 = g_layers.layers(vec!["layer1"]).expect("layer"); @@ -1818,7 +1797,7 @@ mod db_tests { assert!(g_layers2.edge(1, 4).is_none()); let one = g_layers2.node(1).expect("node"); - let ns = one.neighbours().iter().map(|v| v.id()).collect::>(); + let ns = one.neighbours().iter().filter_map(|v| v.id().as_u64()).collect::>(); assert_eq!(ns, vec![2]); }); } @@ -1864,7 +1843,7 @@ mod db_tests { e.edge .layer() .copied() - .map(|layer| (e.src().id(), e.dst().id(), layer)) + .and_then(|layer| Some( (e.src().id().as_u64()?, e.dst().id().as_u64()?, layer) )) }) .collect::>(); diff --git a/raphtory/src/db/graph/nodes.rs b/raphtory/src/db/graph/nodes.rs index f71c68e171..d9657715b9 100644 --- a/raphtory/src/db/graph/nodes.rs +++ b/raphtory/src/db/graph/nodes.rs @@ -6,8 +6,7 @@ use crate::{ state::LazyNodeState, storage::storage_ops::GraphStorage, view::{ - internal::{OneHopFilter, Static}, - BaseNodeViewOps, BoxedLIter, DynamicGraph, IntoDynBoxed, IntoDynamic, + internal::{OneHopFilter, Static}, BaseNodeViewOps, BoxedLIter, DynamicGraph, IntoDynBoxed, IntoDynamic }, }, graph::{edges::NestedEdges, node::NodeView, path::PathFromGraph}, @@ -80,7 +79,13 @@ where g.into_nodes_iter(self.graph.clone(), node_types_filter) } - pub fn iter(&self) -> BoxedLIter<'graph, NodeView> { + pub fn iter(&self) -> impl Iterator> + '_{ + let cg = self.graph.core_graph().lock(); + cg.into_nodes_iter(&self.graph, self.node_types_filter.clone()) + .map(|v| NodeView::new_one_hop_filtered(&self.base_graph, &self.graph, v)) + } + + pub fn iter_owned(&self) -> BoxedLIter<'graph, NodeView> { let base_graph = self.base_graph.clone(); let g = self.graph.clone(); self.iter_refs() @@ -148,7 +153,7 @@ where } pub fn collect(&self) -> Vec> { - self.iter().collect() + self.iter_owned().collect() } pub fn get_const_prop_id(&self, prop_name: &str) -> Option { @@ -269,6 +274,6 @@ where type IntoIter = BoxedLIter<'graph, Self::Item>; fn into_iter(self) -> Self::IntoIter { - Box::new(self.iter()) + Box::new(self.iter_owned()) } } diff --git a/raphtory/src/db/graph/views/deletion_graph.rs b/raphtory/src/db/graph/views/deletion_graph.rs index aaa752176a..beaaa8626a 100644 --- a/raphtory/src/db/graph/views/deletion_graph.rs +++ b/raphtory/src/db/graph/views/deletion_graph.rs @@ -40,30 +40,9 @@ use std::{ /// it is considered active at any point in the window. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PersistentGraph( - #[serde( - deserialize_with = "deserialise_storage", - serialize_with = "serialise_storage" - )] pub GraphStorage, ); -fn deserialise_storage<'de, D>(deserializer: D) -> Result -where - D: serde::Deserializer<'de>, -{ - TemporalGraph::deserialize(deserializer).map(|tg| GraphStorage::Unlocked(Arc::new(tg))) -} - -fn serialise_storage(storage: &GraphStorage, serializer: S) -> Result -where - S: serde::Serializer, -{ - match storage { - GraphStorage::Unlocked(storage) => storage.serialize(serializer), - _ => panic!("Cannot serialise locked storage"), // TODO: fix this at some point - } -} - impl Static for PersistentGraph {} impl From for PersistentGraph { diff --git a/raphtory/src/python/graph/disk_graph.rs b/raphtory/src/python/graph/disk_graph.rs index 5f7ce1b91c..8e1c1848d8 100644 --- a/raphtory/src/python/graph/disk_graph.rs +++ b/raphtory/src/python/graph/disk_graph.rs @@ -1,36 +1,22 @@ -use std::{io::Write, sync::Arc}; - use crate::{ arrow2::{ array::StructArray, datatypes::{ArrowDataType as DataType, Field}, }, - core::{ - entities::{nodes::node_ref::NodeRef, VID}, - utils::errors::GraphError, - }, - db::{ - api::view::{DynamicGraph, IntoDynamic}, - graph::{edge::EdgeView, node::NodeView}, - }, + core::utils::errors::GraphError, disk_graph::{ graph_impl::{DiskGraphStorage, ParquetLayerCols}, - query::{ast::Query, executors::rayon2, state::StaticGraphHopState, NodeSource}, Error, }, - prelude::{EdgeViewOps, Graph, GraphViewOps, NodeViewOps, TimeOps}, python::{ - graph::{edge::PyDirection, graph::PyGraph, views::graph_view::PyGraphView}, - types::repr::StructReprBuilder, - utils::errors::adapt_err_value, + graph::graph::PyGraph, types::repr::StructReprBuilder, utils::errors::adapt_err_value, }, }; use itertools::Itertools; -use pometry_storage::GID; /// A columnar temporal graph. use pyo3::{ prelude::*, - types::{IntoPyDict, PyDict, PyList, PyString}, + types::{PyDict, PyList, PyString}, }; use super::io::pandas_loaders::*; diff --git a/raphtory/src/python/graph/io/pandas_loaders.rs b/raphtory/src/python/graph/io/pandas_loaders.rs index 11ff8b01c0..b211de46a0 100644 --- a/raphtory/src/python/graph/io/pandas_loaders.rs +++ b/raphtory/src/python/graph/io/pandas_loaders.rs @@ -1,5 +1,5 @@ use crate::{ - core::{entities::graph::tgraph::TemporalGraph, utils::errors::GraphError, Prop}, + core::{utils::errors::GraphError, Prop}, db::api::{storage::storage_ops::GraphStorage, view::internal::CoreGraphOps}, io::arrow::{dataframe::*, df_loaders::*}, python::graph::io::*, diff --git a/raphtory/src/python/graph/node.rs b/raphtory/src/python/graph/node.rs index 1921500208..39114e3a89 100644 --- a/raphtory/src/python/graph/node.rs +++ b/raphtory/src/python/graph/node.rs @@ -48,7 +48,7 @@ use python::{ PyGenericIterator, }, }; -use raphtory_api::core::storage::arc_str::ArcStr; +use raphtory_api::core::{entities::GID, storage::arc_str::ArcStr}; use rayon::{iter::IntoParallelIterator, prelude::*}; use std::collections::HashMap; @@ -127,7 +127,7 @@ impl PyNode { /// Returns: /// The id of the node as an integer. #[getter] - pub fn id(&self) -> u64 { + pub fn id(&self) -> GID { self.node.id() } @@ -443,7 +443,7 @@ impl PyNodes { !self.nodes.is_empty() } fn __iter__(&self) -> PyGenericIterator { - self.nodes.iter().into() + self.nodes.iter_owned().into() } #[doc = concat!(" Collect all ","node","s into a list")] #[doc = r""] @@ -496,7 +496,7 @@ impl PyNodes { /// Returns an iterator over the nodes ids #[getter] - fn id(&self) -> LazyNodeState<'static, u64, DynamicGraph, DynamicGraph> { + fn id(&self) -> LazyNodeState<'static, GID, DynamicGraph, DynamicGraph> { self.nodes.id() } diff --git a/raphtory/src/search/mod.rs b/raphtory/src/search/mod.rs index c1160d84c8..ce6efbcc09 100644 --- a/raphtory/src/search/mod.rs +++ b/raphtory/src/search/mod.rs @@ -14,7 +14,7 @@ use tantivy::{ use crate::{ core::{ - entities::{nodes::node_ref::NodeRef, EID, ELID, VID}, + entities::{nodes::node_ref::{AsNodeRef, NodeRef}, EID, ELID, VID}, storage::timeindex::{AsTime, TimeIndexEntry}, utils::errors::GraphError, PropType, @@ -772,8 +772,8 @@ impl InternalAdditionOps for Indexe } #[inline] - fn resolve_node(&self, id: u64, name: Option<&str>) -> VID { - self.graph.resolve_node(id, name) + fn resolve_node(&self, n: V) -> Result { + self.graph.resolve_node(n) } #[inline]