use std::collections::HashMap;
#[must_use]
pub fn needs_quoting(column_name: &str) -> bool {
column_name.contains(' ')
|| column_name.contains('-')
|| column_name.contains('.')
|| column_name.contains('(')
|| column_name.contains(')')
|| column_name.contains('[')
|| column_name.contains(']')
|| column_name.contains('"')
|| column_name.contains('\'')
}
#[must_use]
pub fn quote_if_needed(column_name: &str) -> String {
if needs_quoting(column_name) {
format!("\"{}\"", column_name.replace('"', "\"\""))
} else {
column_name.to_string()
}
}
#[must_use]
pub fn build_column_lookup(headers: &[String]) -> HashMap<String, String> {
let mut lookup = HashMap::new();
for header in headers {
lookup.insert(header.to_lowercase(), header.clone());
}
lookup
}
#[must_use]
pub fn find_column_case_insensitive<'a>(
obj: &'a serde_json::Map<String, serde_json::Value>,
column_name: &str,
lookup: &HashMap<String, String>,
) -> Option<(&'a String, &'a serde_json::Value)> {
if let Some(value) = obj.get_key_value(column_name) {
return Some(value);
}
if let Some(actual_name) = lookup.get(&column_name.to_lowercase()) {
obj.get_key_value(actual_name)
} else {
let column_unquoted = column_name.trim_matches('"');
for (key, value) in obj {
if key == column_unquoted || key.to_lowercase() == column_unquoted.to_lowercase() {
return Some((key, value));
}
}
None
}
}
#[must_use]
pub fn parse_column_name(column: &str) -> &str {
column.trim().trim_matches('"').trim_matches('\'')
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_needs_quoting() {
assert!(!needs_quoting("City"));
assert!(!needs_quoting("customer_id"));
assert!(needs_quoting("Phone 1"));
assert!(needs_quoting("Customer-ID"));
assert!(needs_quoting("Price ($)"));
}
#[test]
fn test_quote_if_needed() {
assert_eq!(quote_if_needed("City"), "City");
assert_eq!(quote_if_needed("Phone 1"), "\"Phone 1\"");
assert_eq!(quote_if_needed("Has\"Quote"), "\"Has\"\"Quote\"");
}
}