app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit b33a3f6bff9a224a61077b668c82aadc621b558d
parent 55554f7ced5df93f1acea3624e72e52422d0fe7d
Author: triesap <triesap@radroots.dev>
Date:   Tue, 20 Jan 2026 23:13:06 +0000

app: add datastore prefix entry retrieval

- extend datastore trait with entries_pref

- implement prefix filtering in web datastore

- update test datastores for new trait method

- add non-wasm test for entries_pref error

Diffstat:
Mapp/src/health.rs | 19+++++++++++++++++++
Mapp/src/logging.rs | 14++++++++++++++
Mcrates/core/src/datastore/types.rs | 4++++
Mcrates/core/src/datastore/web.rs | 24++++++++++++++++++++++--
4 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/app/src/health.rs b/app/src/health.rs @@ -533,6 +533,13 @@ mod tests { datastore_err() } + async fn entries_pref( + &self, + _key_prefix: &str, + ) -> RadrootsClientDatastoreResult<RadrootsClientDatastoreEntries> { + datastore_err() + } + async fn reset(&self) -> RadrootsClientDatastoreResult<()> { datastore_err() } @@ -866,6 +873,18 @@ mod tests { Ok(entries.clone()) } + async fn entries_pref( + &self, + key_prefix: &str, + ) -> RadrootsClientDatastoreResult<RadrootsClientDatastoreEntries> { + let entries = self.entries.lock().unwrap_or_else(|err| err.into_inner()); + Ok(entries + .iter() + .filter(|entry| entry.key.starts_with(key_prefix)) + .cloned() + .collect()) + } + async fn reset(&self) -> RadrootsClientDatastoreResult<()> { Err(RadrootsClientDatastoreError::IdbUndefined) } diff --git a/app/src/logging.rs b/app/src/logging.rs @@ -716,6 +716,20 @@ mod tests { .clone()) } + async fn entries_pref( + &self, + key_prefix: &str, + ) -> RadrootsClientDatastoreResult<RadrootsClientDatastoreEntries> { + Ok(self + .entries + .lock() + .unwrap_or_else(|err| err.into_inner()) + .iter() + .filter(|entry| entry.key.starts_with(key_prefix)) + .cloned() + .collect()) + } + async fn reset(&self) -> RadrootsClientDatastoreResult<()> { Err(RadrootsClientDatastoreError::IdbUndefined) } diff --git a/crates/core/src/datastore/types.rs b/crates/core/src/datastore/types.rs @@ -60,6 +60,10 @@ pub trait RadrootsClientDatastore { ) -> RadrootsClientDatastoreResult<String>; async fn keys(&self) -> RadrootsClientDatastoreResult<Vec<String>>; async fn entries(&self) -> RadrootsClientDatastoreResult<RadrootsClientDatastoreEntries>; + async fn entries_pref( + &self, + key_prefix: &str, + ) -> RadrootsClientDatastoreResult<RadrootsClientDatastoreEntries>; async fn reset(&self) -> RadrootsClientDatastoreResult<()>; async fn export_backup( &self, diff --git a/crates/core/src/datastore/web.rs b/crates/core/src/datastore/web.rs @@ -345,8 +345,16 @@ impl RadrootsClientDatastore for RadrootsClientWebDatastore { } async fn entries(&self) -> RadrootsClientDatastoreResult<RadrootsClientDatastoreEntries> { + self.entries_pref("").await + } + + async fn entries_pref( + &self, + key_prefix: &str, + ) -> RadrootsClientDatastoreResult<RadrootsClientDatastoreEntries> { #[cfg(not(target_arch = "wasm32"))] { + let _ = key_prefix; return Err(RadrootsClientDatastoreError::IdbUndefined); } #[cfg(target_arch = "wasm32")] @@ -357,8 +365,12 @@ impl RadrootsClientDatastore for RadrootsClientWebDatastore { ) .await .map_err(map_idb_error)?; - let mut out = Vec::new(); - for key in keys { + let prefixed: Vec<String> = keys + .into_iter() + .filter(|key| key.starts_with(key_prefix)) + .collect(); + let mut out = Vec::with_capacity(prefixed.len()); + for key in prefixed { let stored = crate::idb::idb_get( self.encrypted_store.get_config().database, self.encrypted_store.get_config().store, @@ -517,4 +529,12 @@ mod tests { .expect_err("idb undefined"); assert_eq!(err, crate::datastore::RadrootsClientDatastoreError::IdbUndefined); } + + #[test] + fn non_wasm_entries_pref_errors() { + let store = RadrootsClientWebDatastore::new(None); + let err = futures::executor::block_on(store.entries_pref("log:")) + .expect_err("idb undefined"); + assert_eq!(err, crate::datastore::RadrootsClientDatastoreError::IdbUndefined); + } }