Implement basic identifier quoting
This commit is contained in:
parent
f11b55b73d
commit
5b2f8eaf9c
@ -31,3 +31,4 @@ default=['postgres']
|
|||||||
postgres=['pg']
|
postgres=['pg']
|
||||||
sqlite=['slite']
|
sqlite=['slite']
|
||||||
mysql=['my']
|
mysql=['my']
|
||||||
|
mssql=[]
|
||||||
|
137
src/drivers.rs
Normal file
137
src/drivers.rs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
//! Drivers
|
||||||
|
//!
|
||||||
|
//! Drivers represent a connection to a specific type of database engine
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[cfg(feature = "postgres")]
|
||||||
|
mod postgres;
|
||||||
|
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
|
mod sqlite;
|
||||||
|
|
||||||
|
#[cfg(feature = "mysql")]
|
||||||
|
mod mysql;
|
||||||
|
|
||||||
|
#[cfg(feature = "mssql")]
|
||||||
|
mod mssql;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Connection;
|
||||||
|
|
||||||
|
/// Result for a db query
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct QueryResult;
|
||||||
|
|
||||||
|
struct DriverBase {
|
||||||
|
escape_char_open: char,
|
||||||
|
escape_char_close: char,
|
||||||
|
has_truncate: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<String>) -> Vec<String> {
|
||||||
|
let mut output: Vec<String> = 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 list,
|
||||||
|
// recurse to quote each identifier in the list
|
||||||
|
if identifier.contains(",") {
|
||||||
|
let mut quoted_parts: Vec<String> = 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 mut trimmed_hiers: Vec<String> = vec![];
|
||||||
|
for hier in identifier.split(".") {
|
||||||
|
let mut hier = &mut hier.trim();
|
||||||
|
|
||||||
|
if hier.starts_with(open_char) && hier.ends_with(close_char) {
|
||||||
|
trimmed_hiers.push(hier.to_string());
|
||||||
|
} else {
|
||||||
|
let mut hier = format!("{}{}{}", open_char, hier, close_char);
|
||||||
|
trimmed_hiers.push(hier.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trimmed_hiers.join(".")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs a basic sql query on the database
|
||||||
|
fn query(&self, query: &str) -> Result<(), ()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TestDriver;
|
||||||
|
|
||||||
|
impl DatabaseDriver for TestDriver {
|
||||||
|
fn query(&self, _query: &str) -> Result<(), ()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_quote_identifier() {
|
||||||
|
let driver = TestDriver {};
|
||||||
|
|
||||||
|
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 = TestDriver {};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
driver.quote_identifiers(vec![
|
||||||
|
"\tfoo. bar".to_string(),
|
||||||
|
"baz".to_string(),
|
||||||
|
"fizz.\n\tbuzz.baz".to_string(),
|
||||||
|
]),
|
||||||
|
vec![
|
||||||
|
r#""foo"."bar""#.to_string(),
|
||||||
|
r#""baz""#.to_string(),
|
||||||
|
r#""fizz"."buzz"."baz""#.to_string(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,57 +0,0 @@
|
|||||||
//! Drivers
|
|
||||||
//!
|
|
||||||
//! Drivers represent a connection to a specific type of database engine
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
#[cfg(feature = "postgres")]
|
|
||||||
mod postgres;
|
|
||||||
|
|
||||||
#[cfg(feature = "sqlite")]
|
|
||||||
mod sqlite;
|
|
||||||
|
|
||||||
#[cfg(feature = "mysql")]
|
|
||||||
mod mysql;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Connection;
|
|
||||||
|
|
||||||
/// Result for a db query
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct QueryResult;
|
|
||||||
|
|
||||||
struct DriverBase {
|
|
||||||
escape_char_open: char,
|
|
||||||
escape_char_close: char,
|
|
||||||
has_truncate: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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<String>) -> Vec<String> {
|
|
||||||
let mut output: Vec<String> = vec![];
|
|
||||||
|
|
||||||
for identifier in identifiers {
|
|
||||||
output.push(self.quote_identifier(&identifier));
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Quote the identifiers passed, so the database does not
|
|
||||||
/// normalize the identifiers (eg, table, column, etc.)
|
|
||||||
fn quote_identifier(&self, identifier: &str) -> String {
|
|
||||||
identifier.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs a basic sql query on the database
|
|
||||||
fn query(&self, query: &str) -> Result<(), ()>;
|
|
||||||
}
|
|
53
src/drivers/mssql.rs
Normal file
53
src/drivers/mssql.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MSSQL;
|
||||||
|
|
||||||
|
impl DatabaseDriver for MSSQL {
|
||||||
|
/// Get which characters are used to delimit identifiers
|
||||||
|
/// such as tables, and columns
|
||||||
|
fn _quotes(&self) -> (char, char) {
|
||||||
|
('[', ']')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query(&self, _query: &str) -> Result<(), ()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_quote_identifier_bracket_quote() {
|
||||||
|
let driver = MSSQL {};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
driver.quote_identifier("foo, bar, baz"),
|
||||||
|
"[foo],[bar],[baz]"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
driver.quote_identifier("foo.bar, baz, fizz"),
|
||||||
|
"[foo].[bar],[baz],[fizz]"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_quote_identifiers_bracket_quote() {
|
||||||
|
let driver = MSSQL {};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
driver.quote_identifiers(vec![
|
||||||
|
"\tfoo. bar".to_string(),
|
||||||
|
"baz".to_string(),
|
||||||
|
"fizz.\n\tbuzz.baz".to_string(),
|
||||||
|
]),
|
||||||
|
vec![
|
||||||
|
"[foo].[bar]".to_string(),
|
||||||
|
"[baz]".to_string(),
|
||||||
|
"[fizz].[buzz].[baz]".to_string(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -7,10 +7,47 @@ impl DatabaseDriver for MySQL {
|
|||||||
/// Get which characters are used to delimit identifiers
|
/// Get which characters are used to delimit identifiers
|
||||||
/// such as tables, and columns
|
/// such as tables, and columns
|
||||||
fn _quotes(&self) -> (char, char) {
|
fn _quotes(&self) -> (char, char) {
|
||||||
('`','`')
|
('`', '`')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query(&self, _query: &str) -> Result<(), ()> {
|
fn query(&self, _query: &str) -> Result<(), ()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_quote_identifier_backtick_quote() {
|
||||||
|
let driver = MySQL {};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
driver.quote_identifier("foo, bar, baz"),
|
||||||
|
"`foo`,`bar`,`baz`"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
driver.quote_identifier("foo.bar, baz, fizz"),
|
||||||
|
"`foo`.`bar`,`baz`,`fizz`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_quote_identifiers_backtick_quote() {
|
||||||
|
let driver = MySQL {};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
driver.quote_identifiers(vec![
|
||||||
|
"\tfoo. bar".to_string(),
|
||||||
|
"baz".to_string(),
|
||||||
|
"fizz.\n\tbuzz.baz".to_string(),
|
||||||
|
]),
|
||||||
|
vec![
|
||||||
|
"`foo`.`bar`".to_string(),
|
||||||
|
"`baz`".to_string(),
|
||||||
|
"`fizz`.`buzz`.`baz`".to_string(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -159,7 +159,7 @@ impl QueryBuilder {
|
|||||||
pub fn select(&mut self, fields: &str) -> &mut Self {
|
pub fn select(&mut self, fields: &str) -> &mut Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the fields to select from the database as a Vector
|
/// Set the fields to select from the database as a Vector
|
||||||
pub fn select_vec(&mut self, fields: Vec<&str>) -> &mut Self {
|
pub fn select_vec(&mut self, fields: Vec<&str>) -> &mut Self {
|
||||||
let fields = fields.join(",");
|
let fields = fields.join(",");
|
||||||
@ -243,7 +243,7 @@ impl QueryBuilder {
|
|||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specify a condition for a `where` clause where a column has a value
|
// Specify a condition for a `where` clause where a column has a value
|
||||||
pub fn where_eq(&mut self, key: &str, value: Box<dyn Any>) -> &mut Self {
|
pub fn where_eq(&mut self, key: &str, value: Box<dyn Any>) -> &mut Self {
|
||||||
self.r#where(key, "=", value)
|
self.r#where(key, "=", value)
|
||||||
|
Loading…
Reference in New Issue
Block a user