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