athena_cli/utils/
filter.rs

1/// Utility functions for filtering collections based on patterns
2pub fn matches_pattern<T: AsRef<str>>(value: T, pattern: &str) -> bool {
3    let value = value.as_ref();
4
5    // Simple wildcard matching
6    if pattern.contains('*') {
7        let parts: Vec<&str> = pattern.split('*').collect();
8
9        // Handle prefix matching (pattern ends with *)
10        if pattern.ends_with('*') && parts.len() == 2 {
11            return value.starts_with(parts[0]);
12        }
13
14        // Handle suffix matching (pattern starts with *)
15        if pattern.starts_with('*') && parts.len() == 2 {
16            return value.ends_with(parts[1]);
17        }
18
19        // Handle contains matching (pattern is *text*)
20        if pattern.starts_with('*') && pattern.ends_with('*') && parts.len() == 3 {
21            return value.contains(parts[1]);
22        }
23    } else {
24        // Default to substring matching instead of exact matching
25        return value.to_lowercase().contains(&pattern.to_lowercase());
26    }
27
28    // Exact matching (only reached if none of the wildcard patterns matched)
29    value == pattern
30}
31
32/// Filter a collection of items based on a pattern
33pub fn filter_items<'a, T, F>(items: &'a [T], pattern: Option<&str>, extractor: F) -> Vec<&'a T>
34where
35    F: Fn(&T) -> &str,
36{
37    match pattern {
38        Some(pattern) => items
39            .iter()
40            .filter(|item| matches_pattern(extractor(item), pattern))
41            .collect(),
42        None => items.iter().collect(),
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    // Define a simple struct to test filtering
51    #[derive(PartialEq, Debug)]
52    struct TestItem {
53        name: String,
54        category: String,
55        count: i32,
56    }
57
58    #[test]
59    fn test_matches_pattern() {
60        // Test exact match
61        assert!(matches_pattern("hello", "hello"));
62
63        // Test substring match (should match if we updated the function)
64        assert!(matches_pattern("hello world", "hello"));
65
66        // Test case insensitivity
67        assert!(matches_pattern("Hello World", "hello"));
68
69        // Test wildcard patterns
70        assert!(matches_pattern("hello world", "hello*"));
71        assert!(matches_pattern("hello world", "*world"));
72        assert!(matches_pattern("hello world", "*lo wor*"));
73
74        // Test non-matches
75        assert!(!matches_pattern("hello", "world"));
76        assert!(!matches_pattern("hello", "hello world"));
77    }
78
79    #[test]
80    fn test_filter_items() {
81        // Create a test vector
82        let items = vec![
83            TestItem {
84                name: "Table1".to_string(),
85                category: "Data".to_string(),
86                count: 10,
87            },
88            TestItem {
89                name: "UserEvents".to_string(),
90                category: "Events".to_string(),
91                count: 20,
92            },
93            TestItem {
94                name: "EventLog".to_string(),
95                category: "Events".to_string(),
96                count: 30,
97            },
98            TestItem {
99                name: "Settings".to_string(),
100                category: "Config".to_string(),
101                count: 40,
102            },
103        ];
104
105        // Test filtering by name
106        let filtered = filter_items(&items, Some("event"), |item| &item.name);
107        assert_eq!(filtered.len(), 2);
108        assert!(filtered.contains(&&items[1])); // UserEvents
109        assert!(filtered.contains(&&items[2])); // EventLog
110
111        // Test filtering by category
112        let filtered = filter_items(&items, Some("events"), |item| &item.category);
113        assert_eq!(filtered.len(), 2);
114        assert!(filtered.contains(&&items[1])); // UserEvents
115        assert!(filtered.contains(&&items[2])); // EventLog
116
117        // Test filtering with wildcard
118        let filtered = filter_items(&items, Some("*Log"), |item| &item.name);
119        assert_eq!(filtered.len(), 1);
120        assert!(filtered.contains(&&items[2])); // EventLog
121
122        // Test filtering with no matches
123        let filtered = filter_items(&items, Some("NonExistent"), |item| &item.name);
124        assert_eq!(filtered.len(), 0);
125
126        // Test with None pattern (should return all items)
127        let filtered = filter_items(&items, None, |item| &item.name);
128        assert_eq!(filtered.len(), items.len());
129    }
130}