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:
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);
+ }
}