timvw commented on code in PR #2394: URL: https://github.com/apache/arrow-datafusion/pull/2394#discussion_r865164594
########## data-access/src/object_store/mod.rs: ########## @@ -102,3 +132,113 @@ pub trait ObjectStore: Sync + Send + Debug { /// Get object reader for one file fn file_reader(&self, file: SizedFile) -> Result<Arc<dyn ObjectReader>>; } + +const GLOB_START_CHARS: [char; 3] = ['?', '*', '[']; + +/// Determine whether the path contains a globbing character +fn contains_glob_start_char(path: &str) -> bool { + path.chars().any(|c| GLOB_START_CHARS.contains(&c)) +} + +/// Filters the file_stream to only contain files that end with suffix +async fn filter_suffix( + file_stream: FileMetaStream, + suffix: &str, +) -> Result<FileMetaStream> { + let suffix = suffix.to_owned(); + Ok(Box::pin(file_stream.filter(move |fr| { + let has_suffix = match fr { + Ok(f) => f.path().ends_with(&suffix), + Err(_) => true, + }; + async move { has_suffix } + }))) +} + +fn find_longest_search_path_without_glob_pattern(glob_pattern: &str) -> String { + // in case the glob_pattern is not actually a glob pattern, take the entire thing + if !contains_glob_start_char(glob_pattern) { + glob_pattern.to_string() + } else { + // take all the components of the path (left-to-right) which do not contain a glob pattern + let components_in_glob_pattern = + Path::new(glob_pattern).components().collect::<Vec<_>>(); + let mut path_buf_for_longest_search_path_without_glob_pattern = PathBuf::new(); + let mut encountered_glob = false; + for component_in_glob_pattern in components_in_glob_pattern { + let component_as_str = + component_in_glob_pattern.as_os_str().to_str().unwrap(); + if !encountered_glob { + let component_str_is_glob = contains_glob_start_char(component_as_str); + encountered_glob = component_str_is_glob; + if !encountered_glob { + path_buf_for_longest_search_path_without_glob_pattern + .push(component_in_glob_pattern); + } + } + } + + let mut result = path_buf_for_longest_search_path_without_glob_pattern + .to_str() + .unwrap() + .to_string(); + // when we're not at the root, append a separator + if path_buf_for_longest_search_path_without_glob_pattern + .components() + .count() + > 1 + { + result.push(path::MAIN_SEPARATOR); + } + result + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_is_glob_path() -> Result<()> { + assert!(!contains_glob_start_char("/")); + assert!(!contains_glob_start_char("/test")); + assert!(!contains_glob_start_char("/test/")); + assert!(contains_glob_start_char("/test*")); + Ok(()) + } + + fn test_longest_base_path(input: &str, expected: &str) { + assert_eq!( + find_longest_search_path_without_glob_pattern(input), + make_expected(input, expected), + "testing find_longest_search_path_without_glob_pattern with {}", + input + ); + } + + fn make_expected(input: &str, expected: &str) -> String { Review Comment: Updated the code such that this updating/fixing of expected values is not needed anymore -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: github-unsubscr...@arrow.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org