summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/core/libimagstore/src/iter.rs118
1 files changed, 118 insertions, 0 deletions
diff --git a/lib/core/libimagstore/src/iter.rs b/lib/core/libimagstore/src/iter.rs
index 1c80d16..78513f9 100644
--- a/lib/core/libimagstore/src/iter.rs
+++ b/lib/core/libimagstore/src/iter.rs
@@ -222,6 +222,31 @@ impl<'a> Entries<'a> {
StoreRetrieveIterator::new(Box::new(self.0.map(|r| r.map(|id| id.without_base()))), self.1)
}
+ /// Find entries where the id contains a substring
+ ///
+ /// This is useful for finding entries if the user supplied only a part of the ID, for example
+ /// if the ID contains a UUID where the user did not specify the full UUID, E.G.:
+ ///
+ /// ```ignore
+ /// imag foo show 827d8596-fad1-4
+ /// ```
+ ///
+ /// # Note
+ ///
+ /// The substring match is done with `contains()`.
+ ///
+ pub fn find_by_id_substr<'b>(self, id_substr: &'b str) -> FindContains<'a, 'b> {
+ FindContains(self, id_substr)
+ }
+
+ /// Find entries where the id starts with a substring
+ ///
+ /// Same as `Entries::find_by_id_substr()`, but using `starts_with()` rather than `contains`.
+ ///
+ pub fn find_by_id_startswith<'b>(self, id_substr: &'b str) -> FindStartsWith<'a, 'b> {
+ FindStartsWith(self, id_substr)
+ }
+
}
impl<'a> Iterator for Entries<'a> {
@@ -232,6 +257,42 @@ impl<'a> Iterator for Entries<'a> {
}
}
+pub struct FindContains<'a, 'b>(Entries<'a>, &'b str);
+
+impl<'a, 'b> Iterator for FindContains<'a, 'b> {
+ type Item = Result<StoreId>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ match self.0.next() {
+ None => return None,
+ Some(Err(e)) => return Some(Err(e)),
+ Some(Ok(next)) => if next.local().to_string_lossy().contains(self.1) {
+ return Some(Ok(next))
+ }, // else loop
+ }
+ }
+ }
+}
+
+pub struct FindStartsWith<'a, 'b>(Entries<'a>, &'b str);
+
+impl<'a, 'b> Iterator for FindStartsWith<'a, 'b> {
+ type Item = Result<StoreId>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ match self.0.next() {
+ None => return None,
+ Some(Err(e)) => return Some(Err(e)),
+ Some(Ok(next)) => if next.local().to_string_lossy().starts_with(self.1) {
+ return Some(Ok(next))
+ }, // else loop
+ }
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
extern crate env_logger;
@@ -281,5 +342,62 @@ mod tests {
assert!(succeeded, "not all entries in iterator are from coll_3 collection");
}
+
+ #[test]
+ fn test_entries_iterator_substr() {
+ setup_logging();
+ let store = get_store();
+
+ let ids = {
+ let base = String::from("entry");
+ let variants = vec!["coll_1", "coll2", "coll_3"];
+ let modifier = |base: &String, v: &&str| {
+ StoreId::new(PathBuf::from(format!("{}/{}", *v, base))).unwrap()
+ };
+
+ generate_variants(&base, variants.iter(), &modifier)
+ };
+
+ for id in ids {
+ let _ = store.retrieve(id).unwrap();
+ }
+
+ let succeeded = store.entries()
+ .unwrap()
+ .find_by_id_substr("_")
+ .map(|id| { debug!("Processing id = {:?}", id); id })
+ .all(|id| id.unwrap().local_display_string().contains('_'));
+
+ assert!(succeeded, "not all entries in iterator contain '_'");
+ }
+
+ #[test]
+ fn test_entries_iterator_startswith() {
+ setup_logging();
+ let store = get_store();
+
+ let ids = {
+ let base = String::from("entry");
+ let variants = vec!["coll_1", "coll2", "coll_3"];
+ let modifier = |base: &String, v: &&str| {
+ StoreId::new(PathBuf::from(format!("{}/{}", *v, base))).unwrap()
+ };
+
+ generate_variants(&base, variants.iter(), &modifier)
+ };
+
+ for id in ids {
+ let _ = store.retrieve(id).unwrap();
+ }
+
+ let succeeded = store.entries()
+ .unwrap()
+ .find_by_id_startswith("entr")
+ .map(|id| { debug!("Processing id = {:?}", id); id })
+ .all(|id| id.unwrap().local_display_string().starts_with("entry"));
+
+ assert!(succeeded, "not all entries in iterator start with 'entr'");
+ }
+
}