pub struct Database { /* private fields */ }Expand description
Main database handle
This is the primary interface for interacting with a CQLite database. It coordinates between the storage engine, schema manager, and query engine.
Implementations§
Source§impl Database
impl Database
Sourcepub async fn open(path: &Path, config: Config) -> Result<Self>
pub async fn open(path: &Path, config: Config) -> Result<Self>
Open a database at the given path with the specified configuration
§Arguments
path- The directory path where the database files will be storedconfig- Database configuration options
§Errors
Returns an error if:
- The path cannot be created or accessed
- Database files are corrupted
- Configuration is invalid
§Examples
use cqlite_core::{Database, Config};
use std::path::{Path, PathBuf};
let config = Config::default();
let db = Database::open(Path::new("./data"), config).await?;Sourcepub async fn open_with_discovered_sstables(
storage_path: &Path,
discovered_table_dirs: Vec<PathBuf>,
config: Config,
) -> Result<Self>
pub async fn open_with_discovered_sstables( storage_path: &Path, discovered_table_dirs: Vec<PathBuf>, config: Config, ) -> Result<Self>
Open a database with pre-discovered SSTable table directories
This method is used in the ingestion flow where SSTable discovery has been performed
externally (e.g., via DiscoveryService) and the database should be initialized with
specific SSTable files rather than scanning the storage directory.
§Use Case
This method is designed for the one-shot ingestion workflow:
DiscoveryService::discover()scans external Cassandra data directoriesSchemaManagerparses schema from discovered filesDatabase::open_with_discovered_sstables()creates a queryable database instance
§Arguments
storage_path- The directory path for database runtime files (WAL, manifest, memtable)discovered_table_dirs- Vector of table directory paths from DiscoveryService (e.g.,/var/lib/cassandra/data/keyspace1/table1-abc123)config- Database configuration options
§Errors
Returns an error if:
- The storage path cannot be created or accessed
- Any discovered table directory cannot be read
- Configuration is invalid
- Storage engine or query engine initialization fails
§Feature Gates
This method is only available when the state_machine feature is enabled (default in M2+).
§Examples
use cqlite_core::{Database, Config};
use std::path::{Path, PathBuf};
let config = Config::default();
let storage_path = Path::new("./runtime");
let discovered_dirs = vec![
PathBuf::from("/var/lib/cassandra/data/keyspace1/table1-abc123"),
PathBuf::from("/var/lib/cassandra/data/keyspace1/table2-def456"),
];
let db = Database::open_with_discovered_sstables(
storage_path,
discovered_dirs,
config
).await?;Sourcepub async fn refresh(&self) -> Result<RefreshReport>
pub async fn refresh(&self) -> Result<RefreshReport>
Re-scan the data directory and atomically apply added/removed SSTable generations to this handle’s reader set (issue #1749).
§Freshness contract
A Database is a snapshot at open: it discovers the
SSTable generations once and never re-scans on its own. A Cassandra
flush/compaction (or a CQLite --flush) may add or remove generations
underneath a warm handle at any time; those changes become visible only
after an explicit refresh(). Re-runs the same TOC/filename-based
discovery open used — no content sniffing, no heuristics.
- Newly present generations become queryable; removed generations stop being queried; unchanged generations keep their warm parsed Index/Statistics/bloom state (not rebuilt).
- In-flight queries are never affected: a scan already running holds
its own
Arcreader clones and completes against the pre-refresh set. A query issued afterrefresh()returns sees the post-refresh set. - Atomic and fail-closed: if any newly discovered generation fails to
open (e.g. a corrupt
Statistics.db, issue #1626),refresh()returns the typed error and leaves the previously held reader set fully unchanged — no partial view.
Returns a RefreshReport describing what this call applied. Explicit
refresh only: there is no filesystem watching or per-query staleness check.
Sourcepub async fn execute(&self, sql: &str) -> Result<QueryResult>
pub async fn execute(&self, sql: &str) -> Result<QueryResult>
Sourcepub async fn execute_streaming(
&self,
sql: &str,
config: StreamingConfig,
) -> Result<QueryResultIterator>
pub async fn execute_streaming( &self, sql: &str, config: StreamingConfig, ) -> Result<QueryResultIterator>
Execute a SQL query with streaming results (Issue #280)
Returns a QueryResultIterator that yields rows incrementally via a bounded
channel, enabling memory-efficient processing of large result sets.
This is the recommended method for exporting large tables, as it avoids materializing all rows in memory at once.
§Arguments
sql- The SQL query to execute (must be a SELECT statement)config- Streaming configuration (buffer size, chunk hints)
§Errors
Returns an error if:
- Query is not a SELECT statement
- SQL syntax is invalid
- Query execution fails
§Examples
let config = StreamingConfig::default();
let mut iter = db.execute_streaming(
"SELECT * FROM large_table",
config
).await?;
while let Some(row_result) = iter.next_async().await {
let row = row_result?;
// Process row incrementally
}Sourcepub async fn execute_with_params(
&self,
sql: &str,
params: &[Value],
) -> Result<QueryResult>
pub async fn execute_with_params( &self, sql: &str, params: &[Value], ) -> Result<QueryResult>
Execute a SELECT with positional ? parameters (Issue #961).
The params are bound, in source order, into the statement’s ?
placeholders before planning, so they participate in partition-key
classification and encoding. A WHERE pk = ? therefore engages the same
partition-targeted fast path as the equivalent literal query.
§Arguments
sql- A SELECT statement that may contain positional?placeholdersparams- Values bound positionally to the?placeholders
§Errors
Returns an error if the SQL is not a SELECT, the parameter count does not
match the number of ? placeholders, or execution fails.
Sourcepub async fn explain(&self, sql: &str) -> Result<ExplainResult>
pub async fn explain(&self, sql: &str) -> Result<ExplainResult>
Sourcepub async fn has_schema_for_table(&self, table: &str) -> bool
pub async fn has_schema_for_table(&self, table: &str) -> bool
Check if schema is available for a table
This is a fast boolean check useful for pre-flight validation.
For detailed diagnostic information, use schema_status().
§Examples
let db = Database::open(std::path::Path::new("./data"), Config::default()).await?;
if !db.has_schema_for_table("users").await {
eprintln!("Warning: No schema found for 'users' table");
}Sourcepub async fn schema_status(&self, table: &str) -> SchemaStatus
pub async fn schema_status(&self, table: &str) -> SchemaStatus
Get detailed schema status for debugging
Returns diagnostic information about schema availability including reasons for missing schemas or extraction failures.
§Examples
let db = Database::open(std::path::Path::new("./data"), Config::default()).await?;
match db.schema_status("users").await {
SchemaStatus::Available { .. } => println!("Schema ready"),
SchemaStatus::ExtractionFailed { cause, suggestion, .. } => {
eprintln!("Schema extraction failed: {}", cause);
eprintln!("Suggestion: {}", suggestion);
}
_ => {}
}Sourcepub async fn stats(&self) -> Result<DatabaseStats>
pub async fn stats(&self) -> Result<DatabaseStats>
Get database statistics
Sourcepub async fn shutdown(&self) -> Result<()>
pub async fn shutdown(&self) -> Result<()>
Shutdown the database storage engine without consuming self.
This is useful for language bindings where the Database is wrapped in an Arc and cannot be consumed. The shutdown operation is idempotent.
For consuming close that also drops the Database, use close().
Sourcepub async fn close(self) -> Result<()>
pub async fn close(self) -> Result<()>
Close the database and release all resources
This method ensures all pending operations are completed and all resources are properly cleaned up.
§Durability contract
Embedders MUST call close().await for a graceful shutdown. Drop is
NOT a flush — Tokio has no async drop, so dropping a handle cannot await
a flush and any un-flushed writer state is left to recovery (WAL replay)
rather than being persisted here. For the write path this maps onto
storage::write_engine::WriteEngine::close, which is the actual
memtable-to-SSTable durability boundary (issue #1693).