pub struct SqliteGraph {
pub pool: PoolManager,
pub hnsw_indexes: RwLock<HashMap<String, HnswIndex>>,
/* private fields */
}Expand description
Embedded SQLite-backed graph database.
Provides a lightweight, deterministic graph database with entity and edge storage, pattern matching, MVCC-lite snapshots, and deterministic indexing.
§Thread Safety
NOT thread-safe for concurrent writes. SqliteGraph uses interior mutability
(RefCell) and is not Sync. However, the underlying connection pool allows
multiple threads to read concurrently when using separate SqliteGraph instances.
§Connection Pooling
File-based databases use an r2d2 connection pool (default 5 connections) for concurrent access. In-memory databases skip pooling and use a single direct connection.
Fields§
§pool: PoolManagerConnection pool for file-based databases, or direct connection for in-memory (public for CLI access to underlying connection)
hnsw_indexes: RwLock<HashMap<String, HnswIndex>>HNSW vector indexes stored by name (public for CLI access)
Implementations§
Source§impl SqliteGraph
impl SqliteGraph
pub fn outgoing_cache_ref(&self) -> &AdjacencyCache
pub fn incoming_cache_ref(&self) -> &AdjacencyCache
Source§impl SqliteGraph
impl SqliteGraph
Sourcepub fn open_with_config<P: AsRef<Path>>(
path: P,
cfg: &SqliteConfig,
) -> Result<Self, SqliteGraphError>
pub fn open_with_config<P: AsRef<Path>>( path: P, cfg: &SqliteConfig, ) -> Result<Self, SqliteGraphError>
Open a graph database with custom configuration.
§Arguments
path- Path to the SQLite database filecfg- Configuration options (pool size, cache size, PRAGMAs, etc.)
§Example
use sqlitegraph::{SqliteGraph, SqliteConfig};
let cfg = SqliteConfig::new()
.with_pool_size(10)
.with_wal_mode();
let graph = SqliteGraph::open_with_config("my_graph.db", &cfg)?;pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, SqliteGraphError>
pub fn open_without_migrations<P: AsRef<Path>>( path: P, ) -> Result<Self, SqliteGraphError>
Sourcepub fn open_in_memory_with_config(
cfg: &SqliteConfig,
) -> Result<Self, SqliteGraphError>
pub fn open_in_memory_with_config( cfg: &SqliteConfig, ) -> Result<Self, SqliteGraphError>
Open an in-memory database with custom configuration.
Note: Pool size is ignored for in-memory databases since they use a single direct connection (each connection would have isolated data).
§Arguments
cfg- Configuration options (cache size, PRAGMAs, etc.)
§Example
use sqlitegraph::{SqliteGraph, SqliteConfig};
let cfg = SqliteConfig::new()
.with_cache_size(256)
.with_performance_mode();
let graph = SqliteGraph::open_in_memory_with_config(&cfg)?;pub fn open_in_memory() -> Result<Self, SqliteGraphError>
pub fn open_in_memory_without_migrations() -> Result<Self, SqliteGraphError>
Sourcepub fn introspect(&self) -> Result<GraphIntrospection, SqliteGraphError>
pub fn introspect(&self) -> Result<GraphIntrospection, SqliteGraphError>
Get comprehensive introspection data for this graph instance.
This method provides a structured snapshot of the graph state, including node counts, edge counts, cache statistics, and file sizes. The result is JSON-serializable for both human debugging and LLM consumption.
§Example
use sqlitegraph::{open_graph, GraphConfig};
let graph = open_graph("my_graph.db", &GraphConfig::sqlite())?;
let intro = graph.introspect()?;
println!("Backend: {}", intro.backend_type);
println!("Nodes: {}", intro.node_count);
println!("Cache hit ratio: {:.2}%", intro.cache_stats.hit_ratio().unwrap_or(0.0));Sourcepub fn cache_stats(&self) -> CacheStats
pub fn cache_stats(&self) -> CacheStats
Get adjacency cache statistics.
Returns combined statistics from both outgoing and incoming adjacency caches. This is useful for monitoring cache effectiveness and tuning cache size.
§Example
use sqlitegraph::{open_graph, GraphConfig};
let graph = open_graph("my_graph.db", &GraphConfig::sqlite())?;
let stats = graph.cache_stats();
println!("Cache hits: {}", stats.hits);
println!("Cache misses: {}", stats.misses);
println!("Hit ratio: {:.2}%", stats.hit_ratio().unwrap_or(0.0));Source§impl SqliteGraph
impl SqliteGraph
pub fn insert_edge(&self, edge: &GraphEdge) -> Result<i64, SqliteGraphError>
pub fn get_edge(&self, id: i64) -> Result<GraphEdge, SqliteGraphError>
pub fn delete_edge(&self, id: i64) -> Result<(), SqliteGraphError>
Source§impl SqliteGraph
impl SqliteGraph
pub fn insert_entity( &self, entity: &GraphEntity, ) -> Result<i64, SqliteGraphError>
pub fn get_entity(&self, id: i64) -> Result<GraphEntity, SqliteGraphError>
pub fn update_entity( &self, entity: &GraphEntity, ) -> Result<(), SqliteGraphError>
pub fn delete_entity(&self, id: i64) -> Result<(), SqliteGraphError>
pub fn list_entity_ids(&self) -> Result<Vec<i64>, SqliteGraphError>
Source§impl SqliteGraph
impl SqliteGraph
pub fn metrics_snapshot(&self) -> GraphMetricsSnapshot
pub fn reset_metrics(&self)
pub fn schema_version(&self) -> Result<i64, SqliteGraphError>
pub fn run_pending_migrations( &self, dry_run: bool, ) -> Result<MigrationReport, SqliteGraphError>
Source§impl SqliteGraph
impl SqliteGraph
Sourcepub fn match_triples(
&self,
pattern: &PatternTriple,
) -> Result<Vec<TripleMatch>, SqliteGraphError>
pub fn match_triples( &self, pattern: &PatternTriple, ) -> Result<Vec<TripleMatch>, SqliteGraphError>
Match lightweight triple patterns using pattern engine.
This method provides a simple interface for matching single-hop patterns like (start_label)-[edge_type]->(end_label) with optional property filters.
§Arguments
pattern- The pattern triple to match
§Returns
A vector of triple matches in deterministic order
Sourcepub fn match_triples_fast(
&self,
pattern: &PatternTriple,
) -> Result<Vec<TripleMatch>, SqliteGraphError>
pub fn match_triples_fast( &self, pattern: &PatternTriple, ) -> Result<Vec<TripleMatch>, SqliteGraphError>
Match lightweight triple patterns using cache-enabled fast-path.
This method provides an optimized version of pattern matching that:
- Uses cache as a fast-path where safe
- Falls back to SQL where pattern requires it
- Returns IDENTICAL results to match_triples()
- Maintains deterministic ordering
§Arguments
pattern- The pattern triple to match
§Returns
A vector of triple matches in deterministic order
Source§impl SqliteGraph
impl SqliteGraph
Sourcepub fn acquire_snapshot(&self) -> Result<GraphSnapshot, SqliteGraphError>
pub fn acquire_snapshot(&self) -> Result<GraphSnapshot, SqliteGraphError>
Acquire a deterministic snapshot of the current graph state
Returns a read-only snapshot that provides isolated access to graph data. The snapshot contains cloned adjacency maps and uses a read-only SQLite connection.
§MVCC-lite Snapshot Isolation
Snapshots provide MVCC-lite isolation guarantees:
- Immutable: Snapshot state never changes after creation
- Consistent: Snapshot sees a point-in-time view of the graph
- Isolated: Snapshot unaffected by subsequent writes
- Cloned Data: Adjacency maps are fully cloned (not shared)
§Cache Requirement
IMPORTANT: Snapshots read from the in-memory adjacency cache, not the database. For accurate snapshots, the cache must be warmed first:
use sqlitegraph::SqliteGraph;
let graph = SqliteGraph::open_in_memory()?;
// ... perform writes ...
// Warm cache before snapshot
let entity_ids = graph.list_entity_ids()?;
for &id in &entity_ids {
let _ = graph.query().outgoing(id);
let _ = graph.query().incoming(id);
}
// Now acquire snapshot
let snapshot = graph.acquire_snapshot()?;
assert!(snapshot.node_count() > 0);Without cache warming, snapshots may appear empty even if the database has data.
§Thread Safety
The underlying SnapshotManager is thread-safe and uses lock-free ArcSwap.
However, SqliteGraph itself is NOT thread-safe (contains RefCell, non-Sync types).
For concurrent snapshot acquisition, wrap SqliteGraph in a Mutex or RwLock:
use std::sync::{Arc, Mutex};
use sqlitegraph::SqliteGraph;
let graph = Arc::new(Mutex::new(SqliteGraph::open_in_memory()?));
// Multiple threads can now safely acquire snapshots§Performance
- Acquisition: < 1ms typical (Arc::clone overhead)
- Memory: O(N + E) where N = nodes, E = edges (full copy)
- Throughput: > 10,000 snapshots/second single-threaded
§Returns
Result containing GraphSnapshot or error
§Errors
Returns error if:
- Read-only SQLite connection cannot be opened
- Database connection fails
Sourcepub fn snapshot(&self) -> Result<GraphSnapshot, SqliteGraphError>
pub fn snapshot(&self) -> Result<GraphSnapshot, SqliteGraphError>
Convenience alias for acquire_snapshot()
This is a shorter name for acquiring snapshots, equivalent to:
let snapshot = graph.snapshot()?;See acquire_snapshot() for full documentation.
Sourcepub fn snapshot_node_count(&self) -> usize
pub fn snapshot_node_count(&self) -> usize
Get the number of nodes in the current snapshot
Note: This requires cache warming to return accurate results.
See acquire_snapshot() documentation for details.
Sourcepub fn snapshot_edge_count(&self) -> usize
pub fn snapshot_edge_count(&self) -> usize
Get the number of edges in the current snapshot
Note: This requires cache warming to return accurate results.
See acquire_snapshot() documentation for details.
Sourcepub fn snapshot_contains_node(&self, node_id: i64) -> bool
pub fn snapshot_contains_node(&self, node_id: i64) -> bool
Check if a node exists in the current snapshot
Note: This requires cache warming to return accurate results.
See acquire_snapshot() documentation for details.
Source§impl SqliteGraph
impl SqliteGraph
Source§impl SqliteGraph
impl SqliteGraph
pub fn query(&self) -> GraphQuery<'_>
§impl SqliteGraph
SQLiteGraph extension for HNSW vector search
impl SqliteGraph
SQLiteGraph extension for HNSW vector search
pub fn hnsw_index(
&self,
name: &str,
config: HnswConfig,
) -> Result<RwLockWriteGuard<'_, HashMap<String, HnswIndex>>, SqliteGraphError>
pub fn hnsw_index( &self, name: &str, config: HnswConfig, ) -> Result<RwLockWriteGuard<'_, HashMap<String, HnswIndex>>, SqliteGraphError>
Create or get an HNSW index with the specified name and configuration
§Arguments
name- Name to identify this index (for multi-index support)config- HNSW configuration parameters
§Returns
Returns a mutable reference to the HnswIndex ready for vector operations
§Examples
use sqlitegraph::{SqliteGraph, hnsw::{HnswConfig, DistanceMetric}};
let graph = SqliteGraph::open_in_memory()?;
let config = HnswConfig::builder()
.dimension(256)
.distance_metric(DistanceMetric::Cosine)
.build()?;
let hnsw = graph.hnsw_index("embeddings", config)?;pub fn hnsw_index_persistent(
&self,
name: &str,
config: HnswConfig,
) -> Result<RwLockWriteGuard<'_, HashMap<String, HnswIndex>>, SqliteGraphError>
pub fn hnsw_index_persistent( &self, name: &str, config: HnswConfig, ) -> Result<RwLockWriteGuard<'_, HashMap<String, HnswIndex>>, SqliteGraphError>
Create or get an HNSW index with persistent storage (for file-based databases)
This method automatically detects if the database is file-based and creates the index with SQLiteVectorStorage for automatic vector persistence. For in-memory databases, falls back to in-memory storage.
§Arguments
name- Name to identify this indexconfig- HNSW configuration parameters
§Returns
Returns a mutable reference to the HnswIndex ready for vector operations
§Examples
use sqlitegraph::{SqliteGraph, hnsw::{HnswConfig, DistanceMetric}};
let graph = SqliteGraph::open("mydb.db")?;
let config = HnswConfig::builder()
.dimension(256)
.distance_metric(DistanceMetric::Cosine)
.build()?;
let hnsw = graph.hnsw_index_persistent("embeddings", config)?;
// Vectors inserted into this index will persist to the databasepub fn get_hnsw_index(
&self,
name: &str,
) -> Result<Option<RwLockWriteGuard<'_, HashMap<String, HnswIndex>>>, SqliteGraphError>
pub fn get_hnsw_index( &self, name: &str, ) -> Result<Option<RwLockWriteGuard<'_, HashMap<String, HnswIndex>>>, SqliteGraphError>
pub fn get_hnsw_index_ref<F, R>(
&self,
name: &str,
f: F,
) -> Result<R, SqliteGraphError>
pub fn get_hnsw_index_ref<F, R>( &self, name: &str, f: F, ) -> Result<R, SqliteGraphError>
Get a reference to an HNSW index without locking for write
pub fn get_hnsw_index_mut<F, R>(
&self,
name: &str,
f: F,
) -> Result<R, SqliteGraphError>
pub fn get_hnsw_index_mut<F, R>( &self, name: &str, f: F, ) -> Result<R, SqliteGraphError>
Get a mutable reference to an HNSW index for modifications
pub fn list_hnsw_indexes(&self) -> Result<Vec<String>, SqliteGraphError>
pub fn list_hnsw_indexes(&self) -> Result<Vec<String>, SqliteGraphError>
List all HNSW index names
Auto Trait Implementations§
impl !Freeze for SqliteGraph
impl !RefUnwindSafe for SqliteGraph
impl !Send for SqliteGraph
impl !Sync for SqliteGraph
impl Unpin for SqliteGraph
impl !UnwindSafe for SqliteGraph
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more