pub struct LpgStore { /* private fields */ }Expand description
The core in-memory graph storage.
Everything lives here: nodes, edges, properties, adjacency indexes, and version chains for MVCC. Concurrent reads never block each other.
Most users should go through GrafeoDB (from the grafeo_engine crate) which
adds transaction management and query execution. Use LpgStore directly
when you need raw performance for algorithm implementations.
§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_core::graph::Direction;
let store = LpgStore::new();
// Create a small social network
let alice = store.create_node(&["Person"]);
let bob = store.create_node(&["Person"]);
store.create_edge(alice, bob, "KNOWS");
// Traverse outgoing edges
for neighbor in store.neighbors(alice, Direction::Outgoing) {
println!("Alice knows node {:?}", neighbor);
}Implementations§
Source§impl LpgStore
impl LpgStore
Sourcepub fn with_config(config: LpgStoreConfig) -> Self
pub fn with_config(config: LpgStoreConfig) -> Self
Creates a new LPG store with custom configuration.
Sourcepub fn current_epoch(&self) -> EpochId
pub fn current_epoch(&self) -> EpochId
Returns the current epoch.
Sourcepub fn create_node(&self, labels: &[&str]) -> NodeId
pub fn create_node(&self, labels: &[&str]) -> NodeId
Creates a new node with the given labels.
Uses the system transaction for non-transactional operations.
Sourcepub fn create_node_versioned(
&self,
labels: &[&str],
epoch: EpochId,
tx_id: TxId,
) -> NodeId
pub fn create_node_versioned( &self, labels: &[&str], epoch: EpochId, tx_id: TxId, ) -> NodeId
Creates a new node with the given labels within a transaction context.
Sourcepub fn create_node_with_props(
&self,
labels: &[&str],
properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>,
) -> NodeId
pub fn create_node_with_props( &self, labels: &[&str], properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>, ) -> NodeId
Creates a new node with labels and properties.
Sourcepub fn create_node_with_props_versioned(
&self,
labels: &[&str],
properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>,
epoch: EpochId,
tx_id: TxId,
) -> NodeId
pub fn create_node_with_props_versioned( &self, labels: &[&str], properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>, epoch: EpochId, tx_id: TxId, ) -> NodeId
Creates a new node with labels and properties within a transaction context.
Sourcepub fn get_node_at_epoch(&self, id: NodeId, epoch: EpochId) -> Option<Node>
pub fn get_node_at_epoch(&self, id: NodeId, epoch: EpochId) -> Option<Node>
Gets a node by ID at a specific epoch.
Sourcepub fn get_node_versioned(
&self,
id: NodeId,
epoch: EpochId,
tx_id: TxId,
) -> Option<Node>
pub fn get_node_versioned( &self, id: NodeId, epoch: EpochId, tx_id: TxId, ) -> Option<Node>
Gets a node visible to a specific transaction.
Sourcepub fn delete_node(&self, id: NodeId) -> bool
pub fn delete_node(&self, id: NodeId) -> bool
Deletes a node and all its edges (using latest epoch).
Sourcepub fn delete_node_at_epoch(&self, id: NodeId, epoch: EpochId) -> bool
pub fn delete_node_at_epoch(&self, id: NodeId, epoch: EpochId) -> bool
Deletes a node at a specific epoch.
Sourcepub fn delete_node_edges(&self, node_id: NodeId)
pub fn delete_node_edges(&self, node_id: NodeId)
Deletes all edges connected to a node (implements DETACH DELETE).
Call this before delete_node() if you want to remove a node that
has edges. Grafeo doesn’t auto-delete edges - you have to be explicit.
Sourcepub fn set_node_property(&self, id: NodeId, key: &str, value: Value)
pub fn set_node_property(&self, id: NodeId, key: &str, value: Value)
Sets a property on a node.
Sourcepub fn set_edge_property(&self, id: EdgeId, key: &str, value: Value)
pub fn set_edge_property(&self, id: EdgeId, key: &str, value: Value)
Sets a property on an edge.
Sourcepub fn remove_node_property(&self, id: NodeId, key: &str) -> Option<Value>
pub fn remove_node_property(&self, id: NodeId, key: &str) -> Option<Value>
Removes a property from a node.
Returns the previous value if it existed, or None if the property didn’t exist.
Sourcepub fn remove_edge_property(&self, id: EdgeId, key: &str) -> Option<Value>
pub fn remove_edge_property(&self, id: EdgeId, key: &str) -> Option<Value>
Removes a property from an edge.
Returns the previous value if it existed, or None if the property didn’t exist.
Sourcepub fn get_node_property(&self, id: NodeId, key: &PropertyKey) -> Option<Value>
pub fn get_node_property(&self, id: NodeId, key: &PropertyKey) -> Option<Value>
Gets a single property from a node without loading all properties.
This is O(1) vs O(properties) for get_node().get_property().
Use this for filter predicates where you only need one property value.
§Example
// Fast: Direct single-property lookup
let age = store.get_node_property(node_id, "age");
// Slow: Loads all properties, then extracts one
let age = store.get_node(node_id).and_then(|n| n.get_property("age").cloned());Sourcepub fn get_edge_property(&self, id: EdgeId, key: &PropertyKey) -> Option<Value>
pub fn get_edge_property(&self, id: EdgeId, key: &PropertyKey) -> Option<Value>
Gets a single property from an edge without loading all properties.
This is O(1) vs O(properties) for get_edge().get_property().
Sourcepub fn get_node_property_batch(
&self,
ids: &[NodeId],
key: &PropertyKey,
) -> Vec<Option<Value>>
pub fn get_node_property_batch( &self, ids: &[NodeId], key: &PropertyKey, ) -> Vec<Option<Value>>
Gets a property for multiple nodes in a single batch operation.
More efficient than calling Self::get_node_property in a loop because it
reduces lock overhead and enables better cache utilization.
§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_common::types::{NodeId, PropertyKey, Value};
let store = LpgStore::new();
let n1 = store.create_node(&["Person"]);
let n2 = store.create_node(&["Person"]);
store.set_node_property(n1, "age", Value::from(25i64));
store.set_node_property(n2, "age", Value::from(30i64));
let ages = store.get_node_property_batch(&[n1, n2], &PropertyKey::new("age"));
assert_eq!(ages, vec![Some(Value::from(25i64)), Some(Value::from(30i64))]);Sourcepub fn get_nodes_properties_batch(
&self,
ids: &[NodeId],
) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
pub fn get_nodes_properties_batch( &self, ids: &[NodeId], ) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
Gets all properties for multiple nodes in a single batch operation.
Returns a vector of property maps, one per node ID (empty map if no properties).
More efficient than calling Self::get_node in a loop.
Sourcepub fn find_nodes_in_range(
&self,
property: &str,
min: Option<&Value>,
max: Option<&Value>,
min_inclusive: bool,
max_inclusive: bool,
) -> Vec<NodeId>
pub fn find_nodes_in_range( &self, property: &str, min: Option<&Value>, max: Option<&Value>, min_inclusive: bool, max_inclusive: bool, ) -> Vec<NodeId>
Finds nodes where a property value is in a range.
This is useful for queries like n.age > 30 or n.price BETWEEN 10 AND 100.
Uses zone maps to skip scanning when the range definitely doesn’t match.
§Arguments
property- The property to checkmin- Optional lower bound (None for unbounded)max- Optional upper bound (None for unbounded)min_inclusive- Whether lower bound is inclusive (>= vs >)max_inclusive- Whether upper bound is inclusive (<= vs <)
§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_common::types::Value;
let store = LpgStore::new();
let n1 = store.create_node(&["Person"]);
let n2 = store.create_node(&["Person"]);
store.set_node_property(n1, "age", Value::from(25i64));
store.set_node_property(n2, "age", Value::from(35i64));
// Find nodes where age > 30
let result = store.find_nodes_in_range(
"age",
Some(&Value::from(30i64)),
None,
false, // exclusive lower bound
true, // inclusive upper bound (doesn't matter since None)
);
assert_eq!(result.len(), 1); // Only n2 matchesSourcepub fn find_nodes_by_properties(
&self,
conditions: &[(&str, Value)],
) -> Vec<NodeId>
pub fn find_nodes_by_properties( &self, conditions: &[(&str, Value)], ) -> Vec<NodeId>
Finds nodes matching multiple property equality conditions.
This is more efficient than intersecting multiple single-property lookups because it can use indexes when available and short-circuits on the first miss.
§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_common::types::Value;
let store = LpgStore::new();
let alice = store.create_node(&["Person"]);
store.set_node_property(alice, "name", Value::from("Alice"));
store.set_node_property(alice, "city", Value::from("NYC"));
// Find nodes where name = "Alice" AND city = "NYC"
let matches = store.find_nodes_by_properties(&[
("name", Value::from("Alice")),
("city", Value::from("NYC")),
]);
assert!(matches.contains(&alice));Sourcepub fn create_property_index(&self, property: &str)
pub fn create_property_index(&self, property: &str)
Creates an index on a node property for O(1) lookups by value.
After creating an index, calls to Self::find_nodes_by_property will be
O(1) instead of O(n) for this property. The index is automatically
maintained when properties are set or removed.
§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_common::types::Value;
let store = LpgStore::new();
// Create nodes with an 'id' property
let alice = store.create_node(&["Person"]);
store.set_node_property(alice, "id", Value::from("alice_123"));
// Create an index on the 'id' property
store.create_property_index("id");
// Now lookups by 'id' are O(1)
let found = store.find_nodes_by_property("id", &Value::from("alice_123"));
assert!(found.contains(&alice));Sourcepub fn drop_property_index(&self, property: &str) -> bool
pub fn drop_property_index(&self, property: &str) -> bool
Drops an index on a node property.
Returns true if the index existed and was removed.
Sourcepub fn has_property_index(&self, property: &str) -> bool
pub fn has_property_index(&self, property: &str) -> bool
Returns true if the property has an index.
Sourcepub fn find_nodes_by_property(
&self,
property: &str,
value: &Value,
) -> Vec<NodeId>
pub fn find_nodes_by_property( &self, property: &str, value: &Value, ) -> Vec<NodeId>
Finds all nodes that have a specific property value.
If the property is indexed, this is O(1). Otherwise, it scans all nodes
which is O(n). Use Self::create_property_index for frequently queried properties.
§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_common::types::Value;
let store = LpgStore::new();
store.create_property_index("city"); // Optional but makes lookups fast
let alice = store.create_node(&["Person"]);
let bob = store.create_node(&["Person"]);
store.set_node_property(alice, "city", Value::from("NYC"));
store.set_node_property(bob, "city", Value::from("NYC"));
let nyc_people = store.find_nodes_by_property("city", &Value::from("NYC"));
assert_eq!(nyc_people.len(), 2);Sourcepub fn add_label(&self, node_id: NodeId, label: &str) -> bool
pub fn add_label(&self, node_id: NodeId, label: &str) -> bool
Adds a label to a node.
Returns true if the label was added, false if the node doesn’t exist or already has the label.
Sourcepub fn remove_label(&self, node_id: NodeId, label: &str) -> bool
pub fn remove_label(&self, node_id: NodeId, label: &str) -> bool
Removes a label from a node.
Returns true if the label was removed, false if the node doesn’t exist or doesn’t have the label.
Sourcepub fn node_count(&self) -> usize
pub fn node_count(&self) -> usize
Returns the number of nodes (non-deleted at current epoch).
Sourcepub fn node_ids(&self) -> Vec<NodeId>
pub fn node_ids(&self) -> Vec<NodeId>
Returns all node IDs in the store.
This returns a snapshot of current node IDs. The returned vector excludes deleted nodes. Results are sorted by NodeId for deterministic iteration order.
Sourcepub fn create_edge(&self, src: NodeId, dst: NodeId, edge_type: &str) -> EdgeId
pub fn create_edge(&self, src: NodeId, dst: NodeId, edge_type: &str) -> EdgeId
Creates a new edge.
Sourcepub fn create_edge_versioned(
&self,
src: NodeId,
dst: NodeId,
edge_type: &str,
epoch: EpochId,
tx_id: TxId,
) -> EdgeId
pub fn create_edge_versioned( &self, src: NodeId, dst: NodeId, edge_type: &str, epoch: EpochId, tx_id: TxId, ) -> EdgeId
Creates a new edge within a transaction context.
Sourcepub fn create_edge_with_props(
&self,
src: NodeId,
dst: NodeId,
edge_type: &str,
properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>,
) -> EdgeId
pub fn create_edge_with_props( &self, src: NodeId, dst: NodeId, edge_type: &str, properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>, ) -> EdgeId
Creates a new edge with properties.
Sourcepub fn get_edge(&self, id: EdgeId) -> Option<Edge>
pub fn get_edge(&self, id: EdgeId) -> Option<Edge>
Gets an edge by ID (latest visible version).
Sourcepub fn get_edge_at_epoch(&self, id: EdgeId, epoch: EpochId) -> Option<Edge>
pub fn get_edge_at_epoch(&self, id: EdgeId, epoch: EpochId) -> Option<Edge>
Gets an edge by ID at a specific epoch.
Sourcepub fn get_edge_versioned(
&self,
id: EdgeId,
epoch: EpochId,
tx_id: TxId,
) -> Option<Edge>
pub fn get_edge_versioned( &self, id: EdgeId, epoch: EpochId, tx_id: TxId, ) -> Option<Edge>
Gets an edge visible to a specific transaction.
Sourcepub fn delete_edge(&self, id: EdgeId) -> bool
pub fn delete_edge(&self, id: EdgeId) -> bool
Deletes an edge (using latest epoch).
Sourcepub fn delete_edge_at_epoch(&self, id: EdgeId, epoch: EpochId) -> bool
pub fn delete_edge_at_epoch(&self, id: EdgeId, epoch: EpochId) -> bool
Deletes an edge at a specific epoch.
Sourcepub fn edge_count(&self) -> usize
pub fn edge_count(&self) -> usize
Returns the number of edges (non-deleted at current epoch).
Sourcepub fn discard_uncommitted_versions(&self, tx_id: TxId)
pub fn discard_uncommitted_versions(&self, tx_id: TxId)
Discards all uncommitted versions created by a transaction.
This is called during transaction rollback to clean up uncommitted changes. The method removes version chain entries created by the specified transaction.
Sourcepub fn label_count(&self) -> usize
pub fn label_count(&self) -> usize
Returns the number of distinct labels in the store.
Sourcepub fn property_key_count(&self) -> usize
pub fn property_key_count(&self) -> usize
Returns the number of distinct property keys in the store.
This counts unique property keys across both nodes and edges.
Sourcepub fn edge_type_count(&self) -> usize
pub fn edge_type_count(&self) -> usize
Returns the number of distinct edge types in the store.
Sourcepub fn neighbors(
&self,
node: NodeId,
direction: Direction,
) -> impl Iterator<Item = NodeId> + '_
pub fn neighbors( &self, node: NodeId, direction: Direction, ) -> impl Iterator<Item = NodeId> + '_
Iterates over neighbors of a node in the specified direction.
This is the fast path for graph traversal - goes straight to the adjacency index without loading full node data.
Sourcepub fn edges_from(
&self,
node: NodeId,
direction: Direction,
) -> impl Iterator<Item = (NodeId, EdgeId)> + '_
pub fn edges_from( &self, node: NodeId, direction: Direction, ) -> impl Iterator<Item = (NodeId, EdgeId)> + '_
Returns edges from a node with their targets.
Returns an iterator of (target_node, edge_id) pairs.
Sourcepub fn out_degree(&self, node: NodeId) -> usize
pub fn out_degree(&self, node: NodeId) -> usize
Returns the out-degree of a node (number of outgoing edges).
Uses the forward adjacency index for O(1) lookup.
Sourcepub fn in_degree(&self, node: NodeId) -> usize
pub fn in_degree(&self, node: NodeId) -> usize
Returns the in-degree of a node (number of incoming edges).
Uses the backward adjacency index for O(1) lookup if available, otherwise falls back to scanning edges.
Sourcepub fn nodes_by_label(&self, label: &str) -> Vec<NodeId>
pub fn nodes_by_label(&self, label: &str) -> Vec<NodeId>
Returns all nodes with a specific label.
Uses the label index for O(1) lookup per label. Returns a snapshot - concurrent modifications won’t affect the returned vector. Results are sorted by NodeId for deterministic iteration order.
Sourcepub fn all_nodes(&self) -> impl Iterator<Item = Node> + '_
pub fn all_nodes(&self) -> impl Iterator<Item = Node> + '_
Returns an iterator over all nodes in the database.
This creates a snapshot of all visible nodes at the current epoch. Useful for dump/export operations.
Sourcepub fn all_edges(&self) -> impl Iterator<Item = Edge> + '_
pub fn all_edges(&self) -> impl Iterator<Item = Edge> + '_
Returns an iterator over all edges in the database.
This creates a snapshot of all visible edges at the current epoch. Useful for dump/export operations.
Sourcepub fn all_labels(&self) -> Vec<String>
pub fn all_labels(&self) -> Vec<String>
Returns all label names in the database.
Sourcepub fn all_edge_types(&self) -> Vec<String>
pub fn all_edge_types(&self) -> Vec<String>
Returns all edge type names in the database.
Sourcepub fn all_property_keys(&self) -> Vec<String>
pub fn all_property_keys(&self) -> Vec<String>
Returns all property keys used in the database.
Sourcepub fn nodes_with_label<'a>(
&'a self,
label: &str,
) -> impl Iterator<Item = Node> + 'a
pub fn nodes_with_label<'a>( &'a self, label: &str, ) -> impl Iterator<Item = Node> + 'a
Returns an iterator over nodes with a specific label.
Sourcepub fn edges_with_type<'a>(
&'a self,
edge_type: &str,
) -> impl Iterator<Item = Edge> + 'a
pub fn edges_with_type<'a>( &'a self, edge_type: &str, ) -> impl Iterator<Item = Edge> + 'a
Returns an iterator over edges with a specific type.
Sourcepub fn node_property_might_match(
&self,
property: &PropertyKey,
op: CompareOp,
value: &Value,
) -> bool
pub fn node_property_might_match( &self, property: &PropertyKey, op: CompareOp, value: &Value, ) -> bool
Checks if a node property predicate might match any nodes.
Uses zone maps for early filtering. Returns true if there might be
matching nodes, false if there definitely aren’t.
Sourcepub fn edge_property_might_match(
&self,
property: &PropertyKey,
op: CompareOp,
value: &Value,
) -> bool
pub fn edge_property_might_match( &self, property: &PropertyKey, op: CompareOp, value: &Value, ) -> bool
Checks if an edge property predicate might match any edges.
Sourcepub fn node_property_zone_map(
&self,
property: &PropertyKey,
) -> Option<ZoneMapEntry>
pub fn node_property_zone_map( &self, property: &PropertyKey, ) -> Option<ZoneMapEntry>
Gets the zone map for a node property.
Sourcepub fn edge_property_zone_map(
&self,
property: &PropertyKey,
) -> Option<ZoneMapEntry>
pub fn edge_property_zone_map( &self, property: &PropertyKey, ) -> Option<ZoneMapEntry>
Gets the zone map for an edge property.
Sourcepub fn rebuild_zone_maps(&self)
pub fn rebuild_zone_maps(&self)
Rebuilds zone maps for all properties.
Sourcepub fn statistics(&self) -> Statistics
pub fn statistics(&self) -> Statistics
Returns the current statistics.
Sourcepub fn compute_statistics(&self)
pub fn compute_statistics(&self)
Recomputes statistics from current data.
Scans all labels and edge types to build cardinality estimates for the query optimizer. Call this periodically or after bulk data loads.
Sourcepub fn estimate_label_cardinality(&self, label: &str) -> f64
pub fn estimate_label_cardinality(&self, label: &str) -> f64
Estimates cardinality for a label scan.
Sourcepub fn estimate_avg_degree(&self, edge_type: &str, outgoing: bool) -> f64
pub fn estimate_avg_degree(&self, edge_type: &str, outgoing: bool) -> f64
Estimates average degree for an edge type.
Sourcepub fn create_node_with_id(&self, id: NodeId, labels: &[&str])
pub fn create_node_with_id(&self, id: NodeId, labels: &[&str])
Creates a node with a specific ID during recovery.
This is used for WAL recovery to restore nodes with their original IDs. The caller must ensure IDs don’t conflict with existing nodes.