//! Drivers //! //! Drivers represent a connection to a specific type of database engine use crate::split_join_map; use std::fmt; #[cfg(feature = "postgres")] pub mod postgres; #[cfg(feature = "sqlite")] pub mod sqlite; #[cfg(feature = "mysql")] pub mod mysql; #[cfg(feature = "mssql")] pub mod mssql; #[derive(Debug)] struct Connection; /// Result for a db query #[derive(Debug)] struct QueryResult; /// Empty Driver implementation /// /// Good for general testing #[derive(Debug)] pub struct DefaultDriver; impl DefaultDriver { pub fn new() -> Self { DefaultDriver {} } } impl DatabaseDriver for DefaultDriver {} /// Database Driver Trait /// /// Interface between the database connection library and the query builder pub trait DatabaseDriver: fmt::Debug { /// Get which characters are used to delimit identifiers /// such as tables, and columns fn _quotes(&self) -> (char, char) { ('"', '"') } /// Vector version of `quote_identifier` fn quote_identifiers(&self, identifiers: Vec<&str>) -> Vec { let mut output: Vec = vec![]; for identifier in identifiers { output.push(self.quote_identifier(identifier).to_string()); } output } /// Quote the identifiers passed, so the database does not /// normalize the identifiers (eg, table, column, etc.) fn quote_identifier(&self, identifier: &str) -> String { let mut identifier = &mut String::from(identifier); // If the identifier is actually a comma-separated list, // recurse to quote each identifier in the list if identifier.contains(",") { let mut quoted_parts: Vec = vec![]; for part in identifier.split(",") { let new_part = part.trim(); let new_part = &self.quote_identifier(new_part); quoted_parts.push(new_part.to_owned()); } // This was the only way I could figure to get // around mutable string reference scope hell identifier.replace_range(.., &mut quoted_parts.join(",")); } let (open_char, close_char) = self._quotes(); let trimmed_tiers = split_join_map(identifier, ".", |tier| { let tier = tier.trim(); // Here where the quoting actually happens. Everything // else is breaking down the identifier list for this. if tier.starts_with(open_char) && tier.ends_with(close_char) { return tier.to_string(); } format!("{}{}{}", &open_char, tier, &close_char) }); trimmed_tiers // @TODO Fix functional calls in 'select' queries } // Runs a basic sql query on the database // fn query(&self, query: &str) -> Result<(), ()>; } #[cfg(test)] mod tests { use super::*; #[test] fn test_quote_identifier() { let driver = DefaultDriver::new(); assert_eq!( driver.quote_identifier("foo, bar, baz"), r#""foo","bar","baz""# ); assert_eq!( driver.quote_identifier("foo.bar, baz, fizz"), r#""foo"."bar","baz","fizz""# ); } #[test] fn test_quote_identifiers() { let driver = DefaultDriver::new(); assert_eq!( driver.quote_identifiers(vec!["\tfoo. bar", "baz", "fizz.\n\tbuzz.baz",]), vec![ r#""foo"."bar""#.to_string(), r#""baz""#.to_string(), r#""fizz"."buzz"."baz""#.to_string(), ] ); } }