Skip to main content

parquet_show_bloom_filter/cli/
mod.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18/// Parses a dot-separated Parquet column path, using `\` as an escape character
19/// for literal dots and backslashes.
20pub fn parse_column_path(path: &str) -> Result<Vec<String>, String> {
21    let mut parts = Vec::new();
22    let mut current = String::new();
23    let mut escaped = false;
24
25    for c in path.chars() {
26        if escaped {
27            match c {
28                '.' | '\\' => current.push(c),
29                _ => {
30                    return Err(format!(
31                        "Invalid escape sequence \\{c} in column path {path}"
32                    ));
33                }
34            }
35            escaped = false;
36            continue;
37        }
38
39        match c {
40            '\\' => escaped = true,
41            '.' => {
42                parts.push(current);
43                current = String::new();
44            }
45            _ => current.push(c),
46        }
47    }
48
49    if escaped {
50        return Err(format!(
51            "Column path {path} ends with an incomplete escape sequence"
52        ));
53    }
54
55    parts.push(current);
56    Ok(parts)
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn parse_column_path_splits_unescaped_dots() {
65        assert_eq!(parse_column_path("a.b.c").unwrap(), vec!["a", "b", "c"]);
66    }
67
68    #[test]
69    fn parse_column_path_allows_escaped_dots() {
70        assert_eq!(parse_column_path(r"a\.b.c").unwrap(), vec!["a.b", "c"]);
71    }
72
73    #[test]
74    fn parse_column_path_allows_escaped_backslashes() {
75        assert_eq!(parse_column_path(r"a\\b.c").unwrap(), vec![r"a\b", "c"]);
76    }
77
78    #[test]
79    fn parse_column_path_invalid_escape_sequence() {
80        let err = parse_column_path(r"a.\b.c").unwrap_err();
81        assert!(err.contains("Invalid escape sequence"));
82    }
83
84    #[test]
85    fn parse_column_path_incomplete_escape_sequence() {
86        let err = parse_column_path(r"a.b.c\").unwrap_err();
87        assert!(err.contains("incomplete escape sequence"));
88    }
89}