pub struct SqlStore { /* private fields */ }Implementations§
Source§impl SqlStore
impl SqlStore
Sourcepub async fn new(connection_string: &str) -> Result<Self, StorageError>
pub async fn new(connection_string: &str) -> Result<Self, StorageError>
Create a new SQL store with startup-mode retry (fails fast if config is wrong).
Sourcepub async fn with_registry(
connection_string: &str,
registry: Arc<SchemaRegistry>,
) -> Result<Self, StorageError>
pub async fn with_registry( connection_string: &str, registry: Arc<SchemaRegistry>, ) -> Result<Self, StorageError>
Create a new SQL store with a shared schema registry.
Use this when you want the SyncEngine to share the registry for dynamic schema registration.
Sourcepub fn pool(&self) -> AnyPool
pub fn pool(&self) -> AnyPool
Get a clone of the connection pool for sharing with other stores.
Sourcepub fn registry(&self) -> &Arc<SchemaRegistry>
pub fn registry(&self) -> &Arc<SchemaRegistry>
Get the schema registry for this store.
Sourcepub async fn ensure_table(&self, table_name: &str) -> Result<(), StorageError>
pub async fn ensure_table(&self, table_name: &str) -> Result<(), StorageError>
Create a schema-specific table with the same structure as sync_items.
Used for horizontal partitioning: each schema (e.g., “users”, “orders”) gets its own table with identical DDL. This enables:
- Better query performance (smaller tables, focused indices)
- Easier maintenance (vacuum, backup per-schema)
- Future sharding potential
For SQLite, this is a no-op (returns Ok) since partitioning doesn’t help.
§Arguments
table_name- Name of the table to create (e.g., “users_items”)
§Example
store.ensure_table("users_items").await.unwrap();
store.ensure_table("orders_items").await.unwrap();Sourcepub async fn table_exists(&self, table_name: &str) -> Result<bool, StorageError>
pub async fn table_exists(&self, table_name: &str) -> Result<bool, StorageError>
Check if a table exists.
Source§impl SqlStore
impl SqlStore
Sourcepub async fn search_in_table(
&self,
table: &str,
where_clause: &str,
params: &[SqlParam],
limit: usize,
) -> Result<Vec<SyncItem>, StorageError>
pub async fn search_in_table( &self, table: &str, where_clause: &str, params: &[SqlParam], limit: usize, ) -> Result<Vec<SyncItem>, StorageError>
Search in a specific table using a WHERE clause.
Sourcepub async fn count_where_in_table(
&self,
table: &str,
where_clause: &str,
params: &[SqlParam],
) -> Result<u64, StorageError>
pub async fn count_where_in_table( &self, table: &str, where_clause: &str, params: &[SqlParam], ) -> Result<u64, StorageError>
Count items in a specific table matching a WHERE clause.
Sourcepub async fn scan_batch(
&self,
limit: usize,
) -> Result<Vec<SyncItem>, StorageError>
pub async fn scan_batch( &self, limit: usize, ) -> Result<Vec<SyncItem>, StorageError>
Scan a batch of items (for WAL drain).
Sourcepub async fn delete_batch(&self, ids: &[String]) -> Result<usize, StorageError>
pub async fn delete_batch(&self, ids: &[String]) -> Result<usize, StorageError>
Delete multiple items by ID in a single query.
Sourcepub async fn get_dirty_merkle_ids(
&self,
limit: usize,
) -> Result<Vec<String>, StorageError>
pub async fn get_dirty_merkle_ids( &self, limit: usize, ) -> Result<Vec<String>, StorageError>
Get IDs of items with merkle_dirty = 1 (need merkle recalculation).
Used by background merkle processor to batch recalculate affected trees.
Sourcepub async fn count_dirty_merkle(&self) -> Result<u64, StorageError>
pub async fn count_dirty_merkle(&self) -> Result<u64, StorageError>
Count items with merkle_dirty = 1.
Sourcepub async fn mark_merkle_clean(
&self,
ids: &[String],
) -> Result<usize, StorageError>
pub async fn mark_merkle_clean( &self, ids: &[String], ) -> Result<usize, StorageError>
Mark items as merkle-clean after recalculation.
Updates all schema-partitioned tables based on the item ID’s routing.
Sourcepub async fn has_dirty_merkle(&self) -> Result<bool, StorageError>
pub async fn has_dirty_merkle(&self) -> Result<bool, StorageError>
Check if there are any dirty merkle items.
Sourcepub async fn branch_dirty_count(
&self,
prefix: &str,
) -> Result<u64, StorageError>
pub async fn branch_dirty_count( &self, prefix: &str, ) -> Result<u64, StorageError>
Count dirty merkle items within a specific branch prefix.
Used for branch-level hygiene checks. Returns 0 if the branch is “clean” (all merkle hashes up-to-date), allowing safe comparison with peers.
§Arguments
prefix- Branch prefix (e.g., “uk.nhs” matches “uk.nhs.patient.123”)
Sourcepub async fn get_dirty_prefixes(&self) -> Result<Vec<String>, StorageError>
pub async fn get_dirty_prefixes(&self) -> Result<Vec<String>, StorageError>
Get distinct top-level prefixes that have dirty items.
Returns prefixes like [“uk”, “us”, “de”] that have pending merkle recalcs. Branches NOT in this list are “clean” and safe to compare with peers.
Sourcepub async fn get_dirty_merkle_items(
&self,
limit: usize,
) -> Result<Vec<SyncItem>, StorageError>
pub async fn get_dirty_merkle_items( &self, limit: usize, ) -> Result<Vec<SyncItem>, StorageError>
Get full SyncItems with merkle_dirty = 1 (need merkle recalculation).
Queries all schema-partitioned tables plus the default table.
Returns the items themselves so merkle can be calculated.
Use mark_merkle_clean() after processing to clear the flag.
Sourcepub async fn get_by_state(
&self,
state: &str,
limit: usize,
) -> Result<Vec<SyncItem>, StorageError>
pub async fn get_by_state( &self, state: &str, limit: usize, ) -> Result<Vec<SyncItem>, StorageError>
Get items by state (e.g., “delta”, “base”, “pending”).
Uses indexed query for fast retrieval.
Sourcepub async fn count_by_state(&self, state: &str) -> Result<u64, StorageError>
pub async fn count_by_state(&self, state: &str) -> Result<u64, StorageError>
Count items in a given state.
Sourcepub async fn list_state_ids(
&self,
state: &str,
limit: usize,
) -> Result<Vec<String>, StorageError>
pub async fn list_state_ids( &self, state: &str, limit: usize, ) -> Result<Vec<String>, StorageError>
Get just the IDs of items in a given state (lightweight query).
Sourcepub async fn set_state(
&self,
id: &str,
new_state: &str,
) -> Result<bool, StorageError>
pub async fn set_state( &self, id: &str, new_state: &str, ) -> Result<bool, StorageError>
Update the state of an item by ID.
Sourcepub async fn delete_by_state(&self, state: &str) -> Result<u64, StorageError>
pub async fn delete_by_state(&self, state: &str) -> Result<u64, StorageError>
Delete all items in a given state.
Returns the number of deleted items.
Sourcepub async fn scan_prefix(
&self,
prefix: &str,
limit: usize,
) -> Result<Vec<SyncItem>, StorageError>
pub async fn scan_prefix( &self, prefix: &str, limit: usize, ) -> Result<Vec<SyncItem>, StorageError>
Sourcepub async fn count_prefix(&self, prefix: &str) -> Result<u64, StorageError>
pub async fn count_prefix(&self, prefix: &str) -> Result<u64, StorageError>
Count items matching an ID prefix.
Sourcepub async fn delete_prefix(&self, prefix: &str) -> Result<u64, StorageError>
pub async fn delete_prefix(&self, prefix: &str) -> Result<u64, StorageError>
Delete all items matching an ID prefix.
Returns the number of deleted items.
Trait Implementations§
Source§impl ArchiveStore for SqlStore
impl ArchiveStore for SqlStore
Source§fn put_batch<'life0, 'life1, 'async_trait>(
&'life0 self,
items: &'life1 mut [SyncItem],
) -> Pin<Box<dyn Future<Output = Result<BatchWriteResult, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn put_batch<'life0, 'life1, 'async_trait>(
&'life0 self,
items: &'life1 mut [SyncItem],
) -> Pin<Box<dyn Future<Output = Result<BatchWriteResult, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Write a batch of items in a single multi-row INSERT with verification.
Items are grouped by target table (based on schema registry) and written in separate batches per table.
fn get<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<SyncItem>, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn put<'life0, 'life1, 'async_trait>(
&'life0 self,
item: &'life1 SyncItem,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn delete<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn exists<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn exists<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn scan_keys<'life0, 'async_trait>(
&'life0 self,
offset: u64,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn scan_keys<'life0, 'async_trait>(
&'life0 self,
offset: u64,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn count_all<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn count_all<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn search<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
where_clause: &'life1 str,
params: &'life2 [SqlParam],
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<SyncItem>, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn search<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
where_clause: &'life1 str,
params: &'life2 [SqlParam],
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<SyncItem>, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§fn count_where<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
where_clause: &'life1 str,
params: &'life2 [SqlParam],
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn count_where<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
where_clause: &'life1 str,
params: &'life2 [SqlParam],
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Auto Trait Implementations§
impl Freeze for SqlStore
impl !RefUnwindSafe for SqlStore
impl Send for SqlStore
impl Sync for SqlStore
impl Unpin for SqlStore
impl !UnwindSafe for SqlStore
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> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
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