sqlitegraph/graph/mod.rs
1//! SQLite-backed graph database implementation.
2//!
3//! This module provides the core graph database implementation with SQLite storage,
4//! entity and edge management, pattern matching, and MVCC-lite snapshot isolation.
5//!
6//! # Module Architecture
7//!
8//! The graph module is organized into focused submodules:
9//!
10//! - **core**: [`SqliteGraph`] - Main graph database implementation
11//! - **types**: [`GraphEntity`], [`GraphEdge`] - Core graph data structures
12//! - **adjacency**: Adjacency list management with caching
13//! - **entity_ops**: Node/entity CRUD operations
14//! - **edge_ops**: Edge/relationship CRUD operations
15//! - **pattern_matching**: Triple pattern matching engine
16//! - **snapshot**: MVCC-lite snapshot system for read isolation
17//! - **metrics**: Performance monitoring and instrumentation
18//!
19//! # Core Types
20//!
21//! - [`SqliteGraph`] - Main graph database struct with dual backend support
22//! - [`GraphEntity`] - Graph node/vertex representation with labels and properties
23//! - [`GraphEdge`] - Graph edge/relationship representation with metadata
24//!
25//! # Invariants and Guarantees
26//
27//! ## Thread Safety
28//!
29//! **NOT thread-safe for concurrent writes.** `SqliteGraph` uses interior mutability
30//! (`RefCell`) and is not `Sync`. Do not share across threads for write operations.
31//!
32//! For concurrent read access, use [`GraphSnapshot`] from the `mvcc` module:
33//!
34//! ```rust,ignore
35//! use sqlitegraph::{GraphSnapshot, SqliteGraph};
36//!
37//! let graph = SqliteGraph::open("my_graph.db")?;
38//!
39//! // Create snapshots for concurrent reads
40//! let snapshot1 = graph.snapshot()?;
41//! let snapshot2 = graph.snapshot()?;
42//!
43//! // Both snapshots can be used concurrently (thread-safe)
44//! std::thread::spawn(move || {
45//! let neighbors = snapshot1.neighbors(node_id)?;
46//! });
47//! ```
48//!
49//! ## Transaction Isolation
50//!
51//! This graph provides **MVCC-lite** snapshot isolation:
52//!
53//! - **Readers** see consistent snapshot at creation time
54//! - **Writers** are serialized (one write transaction at a time)
55//! - **No phantom reads** - snapshots are immutable after creation
56//! - **Write skew** possible - snapshots don't prevent concurrent write conflicts
57//!
58//! MVCC-lite guarantees:
59//! - Readers never block writers
60//! - Writers never block readers
61//! - Each snapshot sees a consistent view
62//! - No dirty reads within a snapshot
63//!
64//! ## Edge Case Behavior
65//!
66//! ### Empty Graph
67//! - Queries on empty graph return empty results (not errors)
68//! - `all_entity_ids()` returns empty `Vec`
69//! - Pattern matching returns empty iterator
70//!
71//! ### Deleted Nodes
72//! - Deleted nodes are removed from all adjacency lists
73//! - Edges to/from deleted nodes are automatically removed
74//! - Subsequent queries return `SqliteGraphError::EntityNotFound`
75//!
76//! ### Self-Loops
77//! - Self-loops (edges where source == target) are supported
78//! - Stored in both incoming and outgoing adjacency lists
79//! - Returned by both `fetch_outgoing` and `fetch_incoming`
80//!
81//! # Performance Characteristics
82//!
83//! ## Insert Operations
84//! - **Node insert**: O(1) amortized (single SQLite INSERT)
85//! - **Edge insert**: O(1) amortized (two SQLite INSERTs + cache update)
86//! - **Bulk insert**: O(N) for batch operations (transaction overhead amortized)
87//!
88//! ## Query Operations
89//! - **Neighbor lookup**: O(degree) for cached adjacency, O(log V) for database query
90//! - **Pattern match**: O(matched triples) with cache acceleration
91//! - **BFS traversal**: O(V + E) worst case, typically O(branching_factor × depth)
92//! - **Shortest path**: O(V + E) for unweighted BFS-based algorithm
93//!
94//! ## Memory Usage
95//! - **Base graph**: O(V + E) for adjacency lists
96//! - **Cache overhead**: O(cached_nodes × avg_degree) for LRU cache
97//! - **Snapshot**: O(1) per snapshot (shares graph data, isolated transaction)
98//!
99//! # Usage Examples
100//!
101//! ## Basic Graph Operations
102//!
103//! ```rust,ignore
104//! use sqlitegraph::{SqliteGraph, GraphEntityCreate};
105//!
106//! let graph = SqliteGraph::open_in_memory()?;
107//!
108//! // Insert nodes
109//! let node1 = graph.insert_node(GraphEntityCreate {
110//! labels: vec!["Person".into()],
111//! properties: vec![],
112//! })?;
113//!
114//! let node2 = graph.insert_node(GraphEntityCreate {
115//! labels: vec!["Person".into()],
116//! properties: vec![],
117//! })?;
118//!
119//! // Insert edge
120//! graph.insert_edge(node1, "KNOWS".into(), node2, vec![])?;
121//!
122//! // Query neighbors
123//! let neighbors = graph.fetch_outgoing(node1)?;
124//! assert_eq!(neighbors, vec![node2]);
125//! ```
126//!
127//! ## Pattern Matching
128//!
129//! ```rust,ignore
130//! use sqlitegraph::{PatternTriple, match_triples};
131//!
132//! let pattern = PatternTriple {
133//! subject: Some(node1),
134//! predicate: Some("KNOWS".into()),
135//! object: None, // Wildcard
136//! };
137//!
138//! let matches = match_triples(&graph, pattern)?;
139//! for triple in matches {
140//! println!("{:?} KNOWS {:?}", triple.subject, triple.object);
141//! }
142//! ```
143//!
144//! # Backend Selection
145//!
146//! This module provides the SQLite backend implementation. For the native backend
147//! (optimized for performance without SQLite dependencies), see `backend::NativeGraphBackend`.
148//!
149//! Both backends implement the `GraphBackend` trait, providing a unified API for
150//! graph operations regardless of storage engine.
151
152pub use self::core::{SqliteGraph, is_in_memory_connection};
153
154mod adjacency;
155mod core;
156mod edge_ops;
157mod entity_ops;
158pub mod pool;
159mod metrics;
160mod metrics_schema;
161mod pattern_matching;
162mod snapshot;
163mod types;
164
165pub use adjacency::{ConnectionWrapper, StatementWrapper};
166pub use metrics::{GraphMetricsSnapshot, InstrumentedConnection};
167pub use types::{GraphEdge, GraphEntity};