datafusion_table_providers/util/
mod.rs1use snafu::prelude::*;
2use std::hash::Hash;
3
4use datafusion::common::DataFusionError;
5use std::collections::HashMap;
6
7use crate::UnsupportedTypeAction;
8
9pub mod column_reference;
10pub mod constraints;
11pub mod indexes;
12pub mod ns_lookup;
13pub mod on_conflict;
14pub mod retriable_error;
15pub mod table_arg_replace;
16
17#[cfg(any(feature = "sqlite", feature = "duckdb", feature = "postgres"))]
18pub mod schema;
19pub mod secrets;
20pub mod test;
21
22#[derive(Debug, Snafu)]
23pub enum Error {
24 #[snafu(display("Unable to generate SQL: {source}"))]
25 UnableToGenerateSQL {
26 source: datafusion::error::DataFusionError,
27 },
28}
29
30#[must_use]
31pub fn hashmap_from_option_string<K, V>(hashmap_option_str: &str) -> HashMap<K, V>
32where
33 K: for<'a> From<&'a str> + Eq + Hash,
34 V: for<'a> From<&'a str> + Default,
35{
36 hashmap_option_str
37 .split(';')
38 .map(|index| {
39 let parts: Vec<&str> = index.split(':').collect();
40 if parts.len() == 2 {
41 (K::from(parts[0]), V::from(parts[1]))
42 } else {
43 (K::from(index), V::default())
44 }
45 })
46 .collect()
47}
48
49#[must_use]
50pub fn remove_prefix_from_hashmap_keys<V>(
51 hashmap: HashMap<String, V>,
52 prefix: &str,
53) -> HashMap<String, V> {
54 hashmap
55 .into_iter()
56 .map(|(key, value)| {
57 let new_key = key
58 .strip_prefix(prefix)
59 .map_or(key.clone(), |s| s.to_string());
60 (new_key, value)
61 })
62 .collect()
63}
64
65#[must_use]
66pub fn to_datafusion_error<E>(error: E) -> DataFusionError
67where
68 E: std::error::Error + Send + Sync + 'static,
69{
70 DataFusionError::External(Box::new(error))
71}
72
73pub fn handle_unsupported_type_error<E>(
85 unsupported_type_action: UnsupportedTypeAction,
86 error: E,
87) -> Result<(), E>
88where
89 E: std::error::Error + Send + Sync,
90{
91 match unsupported_type_action {
92 UnsupportedTypeAction::Error | UnsupportedTypeAction::String => return Err(error),
93 UnsupportedTypeAction::Warn => {
94 tracing::warn!("{error}");
95 }
96 UnsupportedTypeAction::Ignore => {}
97 };
98
99 Ok(())
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use std::collections::HashMap;
106
107 #[test]
108 fn test_remove_prefix() {
109 let mut hashmap = HashMap::new();
110 hashmap.insert("prefix_key1".to_string(), "value1".to_string());
111 hashmap.insert("prefix_key2".to_string(), "value2".to_string());
112 hashmap.insert("key3".to_string(), "value3".to_string());
113
114 let result = remove_prefix_from_hashmap_keys(hashmap, "prefix_");
115
116 let mut expected = HashMap::new();
117 expected.insert("key1".to_string(), "value1".to_string());
118 expected.insert("key2".to_string(), "value2".to_string());
119 expected.insert("key3".to_string(), "value3".to_string());
120
121 assert_eq!(result, expected);
122 }
123
124 #[test]
125 fn test_no_prefix() {
126 let mut hashmap = HashMap::new();
127 hashmap.insert("key1".to_string(), "value1".to_string());
128 hashmap.insert("key2".to_string(), "value2".to_string());
129
130 let result = remove_prefix_from_hashmap_keys(hashmap, "prefix_");
131
132 let mut expected = HashMap::new();
133 expected.insert("key1".to_string(), "value1".to_string());
134 expected.insert("key2".to_string(), "value2".to_string());
135
136 assert_eq!(result, expected);
137 }
138
139 #[test]
140 fn test_empty_hashmap() {
141 let hashmap: HashMap<String, String> = HashMap::new();
142
143 let result = remove_prefix_from_hashmap_keys(hashmap, "prefix_");
144
145 let expected: HashMap<String, String> = HashMap::new();
146
147 assert_eq!(result, expected);
148 }
149
150 #[test]
151 fn test_full_prefix() {
152 let mut hashmap = HashMap::new();
153 hashmap.insert("prefix_".to_string(), "value1".to_string());
154 hashmap.insert("prefix_key2".to_string(), "value2".to_string());
155
156 let result = remove_prefix_from_hashmap_keys(hashmap, "prefix_");
157
158 let mut expected = HashMap::new();
159 expected.insert("".to_string(), "value1".to_string());
160 expected.insert("key2".to_string(), "value2".to_string());
161
162 assert_eq!(result, expected);
163 }
164}