More implementation

This commit is contained in:
Timothy Warren 2019-04-12 17:09:59 -04:00
parent 4cc6f079c3
commit f7efadeb66
10 changed files with 148 additions and 30 deletions

View File

@ -28,14 +28,9 @@ version="15.1.0"
optional=true optional=true
package="mysql" package="mysql"
[dependencies.ms]
version="0.3.2"
optional=true
package="tiberius"
[features] [features]
default=['postgres'] default=['postgres']
postgres=['pg'] postgres=['pg']
sqlite=['slite'] sqlite=['slite']
mysql=['my'] mysql=['my']
mssql=['ms'] mssql=[]

View File

@ -37,7 +37,15 @@ impl DefaultDriver {
} }
} }
impl DatabaseDriver for DefaultDriver {} impl DatabaseDriver for DefaultDriver {
fn explain(&self, sql: &str) -> String {
return format!("EXPLAIN {}", sql)
}
fn random(&self) -> String {
String::from(" RANDOM")
}
}
/// Database Driver Trait /// Database Driver Trait
/// ///
@ -96,6 +104,32 @@ pub trait DatabaseDriver: fmt::Debug {
// Runs a basic sql query on the database // Runs a basic sql query on the database
// fn query(&self, query: &str) -> Result<(), ()>; // fn query(&self, query: &str) -> Result<(), ()>;
// ------------------------------------------------------------------------
// ! Driver-specific SQL methods
// ------------------------------------------------------------------------
/// Take an existing sql query and add a limit and/or offset
fn limit(&self, sql: &str, limit: Option<usize>, offset: Option<usize>) -> String {
let mut sql = sql.to_string();
if limit.is_some() {
sql += &format!("\nLIMIT {}", limit.unwrap());
}
if offset.is_some() {
sql += &format!(" OFFSET {}", offset.unwrap());
}
sql
}
/// Get the query plan for the existing sql
fn explain(&self, sql: &str) -> String;
/// Get the database's keyword for sorting randomly
fn random(&self) -> String;
} }
#[cfg(test)] #[cfg(test)]

View File

@ -1,5 +1,8 @@
//! Database Driver for MSSQL //! Database Driver for MSSQL
//! //!
//! Note:
//! **This driver will probably never be fully implemented**
//!
//! Contains database-specific query data //! Contains database-specific query data
use super::*; use super::*;
@ -20,6 +23,14 @@ impl DatabaseDriver for MSSQL {
fn _quotes(&self) -> (char, char) { fn _quotes(&self) -> (char, char) {
('[', ']') ('[', ']')
} }
fn explain(&self, sql: &str) -> String {
sql.to_string()
}
fn random(&self) -> String {
String::from(" RANDOM")
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -5,21 +5,43 @@ use super::*;
/// The struct implementing the `DatabaseDriver` trait /// The struct implementing the `DatabaseDriver` trait
#[derive(Debug)] #[derive(Debug)]
pub struct MySQL; pub struct MySQLDriver;
impl MySQL { impl MySQLDriver {
/// Create a MySQL driver /// Create a MySQLDriver driver
pub fn new() -> Self { pub fn new() -> Self {
MySQL {} MySQLDriver {}
} }
} }
impl DatabaseDriver for MySQL { impl DatabaseDriver for MySQLDriver {
/// 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 limit(&self, sql: &str, limit: Option<usize>, offset: Option<usize>) -> String {
if limit.is_none() {
return sql.to_string();
}
// Limit and Offset are defined
if offset.is_some() {
return format!("{} LIMIT {}.{}", sql, offset.unwrap(), limit.unwrap());
}
// Limit is defined
format!("{} LIMIT {}", sql, limit.unwrap())
}
fn explain(&self, sql: &str) -> String {
return format!("EXPLAIN EXTENDED {}", sql)
}
fn random(&self) -> String {
String::from(" RAND() DESC")
}
} }
#[cfg(test)] #[cfg(test)]
@ -28,7 +50,7 @@ mod tests {
#[test] #[test]
fn test_quote_identifier_backtick_quote() { fn test_quote_identifier_backtick_quote() {
let driver = MySQL::new(); let driver = MySQLDriver::new();
assert_eq!( assert_eq!(
driver.quote_identifier("foo, bar, baz"), driver.quote_identifier("foo, bar, baz"),
@ -42,7 +64,7 @@ mod tests {
#[test] #[test]
fn test_quote_identifiers_backtick_quote() { fn test_quote_identifiers_backtick_quote() {
let driver = MySQL::new(); let driver = MySQLDriver::new();
assert_eq!( assert_eq!(
driver.quote_identifiers(vec![ driver.quote_identifiers(vec![

View File

@ -5,13 +5,21 @@ use super::*;
/// The struct implementing the `DatabaseDriver` trait /// The struct implementing the `DatabaseDriver` trait
#[derive(Debug)] #[derive(Debug)]
pub struct Postgres; pub struct PostgresDriver;
impl Postgres { impl PostgresDriver {
/// Create a Postgres driver /// Create a PostgresDriver driver
pub fn new() -> Self { pub fn new() -> Self {
Postgres {} PostgresDriver {}
} }
} }
impl DatabaseDriver for Postgres {} impl DatabaseDriver for PostgresDriver {
fn explain(&self, sql: &str) -> String {
return format!("EXPLAIN VERBOSE {}", sql)
}
fn random(&self) -> String {
String::from(" RANDOM()")
}
}

View File

@ -5,13 +5,22 @@ use super::*;
/// The struct implementing the `DatabaseDriver` trait /// The struct implementing the `DatabaseDriver` trait
#[derive(Debug)] #[derive(Debug)]
pub struct SQLite; pub struct SQLiteDriver;
impl SQLite { impl SQLiteDriver {
/// Create an SQLite driver /// Create an SQLiteDriver driver
pub fn new() -> Self { pub fn new() -> Self {
SQLite {} SQLiteDriver {}
}
}
impl DatabaseDriver for SQLiteDriver {
fn explain(&self, sql: &str) -> String {
return format!("EXPLAIN QUERY PLAN {}", sql)
}
fn random(&self) -> String {
String::from(" RANDOM()")
} }
} }
impl DatabaseDriver for SQLite {}

View File

@ -17,7 +17,21 @@ pub mod query_builder;
pub mod prelude { pub mod prelude {
//! Re-exports important traits and types. //! Re-exports important traits and types.
//!
//! This includes enum types, traits,
//! the Query Builder, and individual database drivers.
pub use crate::enums::*; pub use crate::enums::*;
pub use crate::drivers::{DatabaseDriver, DefaultDriver}; pub use crate::drivers::DatabaseDriver;
pub use crate::query_builder::QueryBuilder; pub use crate::query_builder::QueryBuilder;
#[cfg(feature = "postgres")]
pub use crate::drivers::postgres::PostgresDriver;
#[cfg(feature = "sqlite")]
pub use crate::drivers::sqlite::SQLiteDriver;
#[cfg(feature = "mysql")]
pub use crate::drivers::mysql::MySQLDriver;
// MSSQL is missing on purpose, as it is not a real priority to actually implement
} }

View File

@ -1,10 +1,8 @@
//! This main file is just for temparary testing //! This main file is just for temparary testing
use stringqb::drivers::postgres::Postgres; use stringqb::prelude::*;
use stringqb::query_builder::QueryBuilder;
// use stringqb::types::{SQLType, Type};
fn main() { fn main() {
let mut qb = QueryBuilder::new(Postgres::new()); let mut qb = QueryBuilder::new(PostgresDriver::new());
qb.set("foo", Box::new("bar")) qb.set("foo", Box::new("bar"))
.set("bar", Box::new(12)) .set("bar", Box::new(12))

View File

@ -53,6 +53,13 @@ impl QueryBuilder {
/// ///
/// // The query builder must be mutable to be useful /// // The query builder must be mutable to be useful
/// let mut qb = QueryBuilder::new(DefaultDriver::new()); /// let mut qb = QueryBuilder::new(DefaultDriver::new());
///
/// // Each builder method returns a mutable reference to itself so
/// // the methods are chainable
/// qb.select("field f").from("table");
///
/// // Since they are references, you do not have to chain.
/// let sql = qb.get_compiled_select();
/// ``` /// ```
pub fn new(driver: impl DatabaseDriver + 'static) -> Self { pub fn new(driver: impl DatabaseDriver + 'static) -> Self {
QueryBuilder { QueryBuilder {

View File

@ -1,4 +1,4 @@
use stringqb::query_builder::QueryBuilder; use stringqb::prelude::*;
#[test] #[test]
fn minimal_select_query() { fn minimal_select_query() {
@ -47,6 +47,26 @@ fn select_without_from() {
qb.get_compiled_select(); qb.get_compiled_select();
} }
#[test]
fn select_where_in() {
let mut qb = QueryBuilder::default();
qb.from("test")
.where_in("foo", vec![
Box::new(0),
Box::new(1),
Box::new(2),
Box::new(3),
Box::new(4),
Box::new(5)
]);
let sql = qb.get_compiled_select();
let expected = "SELECT *\nFROM \"test\" WHERE \"foo\" IN (?,?,?,?,?,?) ";
assert_eq!(sql, expected);
}
#[test] #[test]
fn basic_insert_query() { fn basic_insert_query() {
let mut qb = QueryBuilder::default(); let mut qb = QueryBuilder::default();