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 !RefUnwindSafe for SqlStore
impl !UnwindSafe for SqlStore
impl Freeze for SqlStore
impl Send for SqlStore
impl Sync for SqlStore
impl Unpin for SqlStore
impl UnsafeUnpin 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