diff --git a/graph/src/graph/attribute_store.rs b/graph/src/graph/attribute_store.rs index ba4093e4..a9d1a534 100644 --- a/graph/src/graph/attribute_store.rs +++ b/graph/src/graph/attribute_store.rs @@ -526,6 +526,34 @@ impl AttributeStore { self.cache.memory_usage() } + /// Bulk import attributes for entities known to be new (no prior state). + /// + /// Optimized for RDB decode: skips cache/fjall lookups since entities + /// don't exist yet. Attributes are written directly to cache. + pub fn import_attrs( + &mut self, + attrs: &HashMap, Value>>, + ) { + for (key, entity_attrs) in attrs { + let mut entries: Vec<(u16, Value)> = Vec::with_capacity(entity_attrs.len()); + + for (attr, value) in entity_attrs.iter() { + if matches!(value, Value::Null) { + continue; + } + let idx = self.attrs_name.get_index_of(attr).unwrap_or_else(|| { + self.attrs_name.insert(attr.clone()); + self.attrs_name.len() - 1 + }) as u16; + entries.push((idx, value.clone())); + } + + entries.sort_by_key(|(idx, _)| *idx); + self.cache.insert_entity(*key, entries, self.version, true); + self.dirty_entities.insert(*key); + } + } + pub fn commit(&mut self) -> Result<(), String> { // Apply pending full entity deletions to fjall. if !self.pending_deletes.is_empty() { diff --git a/graph/src/graph/graph.rs b/graph/src/graph/graph.rs index 143d81fe..d6b73975 100644 --- a/graph/src/graph/graph.rs +++ b/graph/src/graph/graph.rs @@ -858,6 +858,22 @@ impl Graph { self.node_count + self.deleted_nodes.len() - 1 } + /// Bulk import node attributes (for RDB decode, skips indexing/cache lookup). + pub fn import_node_attrs( + &mut self, + attrs: &HashMap, Value>>, + ) { + self.node_attrs.import_attrs(attrs); + } + + /// Bulk import relationship attributes (for RDB decode). + pub fn import_relationship_attrs( + &mut self, + attrs: &HashMap, Value>>, + ) { + self.relationship_attrs.import_attrs(attrs); + } + #[must_use] pub fn max_relationship_id(&self) -> u64 { if self.relationship_count == 0 { diff --git a/graph/src/runtime/ops/set.rs b/graph/src/runtime/ops/set.rs index eaa80b6c..6766152d 100644 --- a/graph/src/runtime/ops/set.rs +++ b/graph/src/runtime/ops/set.rs @@ -264,7 +264,8 @@ impl Runtime<'_> { } } Value::Relationship(target_rel) => { - if self.g.borrow().is_relationship_deleted(target_rel.0) + if (self.g.borrow().is_relationship_deleted(target_rel.0) + && !self.pending.borrow().is_relationship_created(target_rel.0)) || self.pending.borrow().is_relationship_deleted( target_rel.0, target_rel.1, diff --git a/graph/src/runtime/pending.rs b/graph/src/runtime/pending.rs index e4760ae8..231a2ea0 100644 --- a/graph/src/runtime/pending.rs +++ b/graph/src/runtime/pending.rs @@ -73,7 +73,11 @@ fn is_valid_property( | Value::Float(_) | Value::String(_) | Value::Point(_) - | Value::VecF32(_) => true, + | Value::VecF32(_) + | Value::Datetime(_) + | Value::Date(_) + | Value::Time(_) + | Value::Duration(_) => true, Value::List(items) => items.iter().all(|v| is_valid_property(v, false)), _ => false, }