diff --git a/src/blob_tree/mod.rs b/src/blob_tree/mod.rs index 3058ef55..e389ae42 100644 --- a/src/blob_tree/mod.rs +++ b/src/blob_tree/mod.rs @@ -58,6 +58,27 @@ impl IterGuard for Guard { } } + fn into_inner_if_some( + self, + pred: impl Fn(&UserKey) -> Option, + ) -> crate::Result> { + let kv = self.kv?; + + if let Some(t) = pred(&kv.key.user_key) { + resolve_value_handle( + self.tree.id(), + self.tree.blobs_folder.as_path(), + &self.tree.index.config.cache, + &self.tree.index.config.descriptor_table, + &self.version, + kv, + ) + .map(|(_, v)| Some((t, v))) + } else { + Ok(None) + } + } + fn key(self) -> crate::Result { self.kv.map(|kv| kv.key.user_key) } diff --git a/src/iter_guard.rs b/src/iter_guard.rs index 63fb9312..93081c6e 100644 --- a/src/iter_guard.rs +++ b/src/iter_guard.rs @@ -19,6 +19,19 @@ pub trait IterGuard { pred: impl Fn(&UserKey) -> bool, ) -> crate::Result<(UserKey, Option)>; + /// Accesses the key-value pair if the predicate returns `Some(T)`. + /// + /// The predicate receives the key - if returning None, the value + /// may not be loaded if the tree is key-value separated. + /// + /// # Errors + /// + /// Will return `Err` if an IO error occurs. + fn into_inner_if_some( + self, + pred: impl Fn(&UserKey) -> Option, + ) -> crate::Result>; + /// Accesses the key-value pair. /// /// # Errors diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 4c804083..518c613d 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -49,6 +49,19 @@ impl IterGuard for Guard { } } + fn into_inner_if_some( + self, + pred: impl Fn(&UserKey) -> Option, + ) -> crate::Result> { + let (k, v) = self.0?; + + if let Some(t) = pred(&k) { + Ok(Some((t, v))) + } else { + Ok(None) + } + } + fn key(self) -> crate::Result { self.0.map(|(k, _)| k) } diff --git a/tests/guard_if.rs b/tests/guard_if.rs index 6072d5d0..ad654e47 100644 --- a/tests/guard_if.rs +++ b/tests/guard_if.rs @@ -69,3 +69,80 @@ fn guard_into_inner_if_blob() -> lsm_tree::Result<()> { Ok(()) } + +#[test] +fn guard_into_inner_if_some() -> lsm_tree::Result<()> { + let folder = get_tmp_folder(); + + { + let tree = Config::new( + &folder, + SequenceNumberCounter::default(), + SequenceNumberCounter::default(), + ) + .open()?; + + tree.insert("earth#name", "earth", 0); + tree.insert("earth#color", "BLUE", 0); + + assert_eq!(2, tree.iter(SeqNo::MAX, None).count()); + + assert_eq!( + 1, + tree.iter(SeqNo::MAX, None) + .filter_map(|guard| { + guard + .into_inner_if_some(|key| { + if key.ends_with(b"#name") { + Some(()) + } else { + None + } + }) + .unwrap() + }) + .count(), + ); + } + + Ok(()) +} + +#[test] +fn guard_into_inner_if_some_blob() -> lsm_tree::Result<()> { + let folder = get_tmp_folder(); + + { + let tree = Config::new( + &folder, + SequenceNumberCounter::default(), + SequenceNumberCounter::default(), + ) + .with_kv_separation(Some(KvSeparationOptions::default().separation_threshold(1))) + .open()?; + + tree.insert("earth#name", "earth", 0); + tree.insert("earth#color", "BLUE", 0); + + assert_eq!(2, tree.iter(SeqNo::MAX, None).count()); + + assert_eq!( + 1, + tree.iter(SeqNo::MAX, None) + .filter_map(|guard| { + guard + .into_inner_if_some(|key| { + if key.ends_with(b"#name") { + Some(()) + } else { + None + } + }) + .unwrap() + }) + .count(), + ); + } + + Ok(()) +}