Skip to main content

uqa_storage/catalog/
graph_observations.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Logical graph payload addresses shared by semantic readers and evaluated provider mutations.
8
9mod definitions;
10mod labels;
11mod topology;
12
13pub use definitions::{GraphDefinitionKey, GraphDefinitionKind};
14pub use labels::{observe_label_registry_change, GraphLabelDefinitionKey, GraphLabelName};
15pub use topology::{GraphEntityTopology, GraphMembershipKey, GraphSelectionKey};
16
17use super::graph_identifiers::GraphIdentifierNamespace;
18use crate::mvcc::{SerializableKeySpace, SerializablePredicate};
19use crate::{GraphEntityKind, KeyValueBatch, StorageBackendResult};
20
21/// Observe the physical scope lifetime separately from entity generations. Ordinary entity changes do not write this key; replacing the clear generation does.
22pub fn scope_lifetime(namespace: GraphIdentifierNamespace) -> SerializablePredicate<'static> {
23    SerializablePredicate::point(
24        namespace.serializable_scope_object(),
25        SerializableKeySpace::Graph,
26        b"clear",
27    )
28}
29
30/// A global entity may belong to several named graphs. Payload reads and writes meet at its original physical scope and clear generation, while vertex and edge identities remain disjoint.
31#[derive(Clone, Copy)]
32pub struct GraphEntityKey {
33    object: [u8; 16],
34    key: [u8; 10],
35}
36
37impl GraphEntityKey {
38    pub fn new(namespace: GraphIdentifierNamespace, kind: GraphEntityKind, id: u64) -> Self {
39        let mut key = [0; 10];
40        key[0] = b'p';
41        key[1] = match kind {
42            GraphEntityKind::Vertex => b'v',
43            GraphEntityKind::Edge => b'e',
44        };
45        key[2..].copy_from_slice(&id.to_be_bytes());
46        Self {
47            object: namespace.serializable_entity_object(),
48            key,
49        }
50    }
51
52    pub fn predicate(&self) -> SerializablePredicate<'_> {
53        SerializablePredicate::point(self.object, SerializableKeySpace::Graph, &self.key)
54    }
55
56    pub fn observe_write(&self, batch: &mut dyn KeyValueBatch) -> StorageBackendResult<()> {
57        batch.observe_serializable_write(self.predicate())
58    }
59}