Yet another ugly progress commit
This commit is contained in:
parent
25da0ae57e
commit
6ca96315cc
@ -29,7 +29,11 @@ package="mysql"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default=['postgres']
|
default=['postgres']
|
||||||
|
docs-rs=['postgres', 'sqlite', 'mysql']
|
||||||
postgres=['pg']
|
postgres=['pg']
|
||||||
sqlite=['slite']
|
sqlite=['slite']
|
||||||
mysql=['my']
|
mysql=['my']
|
||||||
mssql=[]
|
mssql=[]
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
features=['docs-rs']
|
@ -121,6 +121,12 @@ pub trait DatabaseDriver {
|
|||||||
// ! Driver-specific SQL methods
|
// ! Driver-specific SQL methods
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Return the sql to empty a table
|
||||||
|
fn truncate(&self, table: &str) -> String {
|
||||||
|
String::from("TRUNCATE TABLE ")
|
||||||
|
+ &self.quote_identifier(table)
|
||||||
|
}
|
||||||
|
|
||||||
/// Take an existing sql query and add a limit and/or offset
|
/// Take an existing sql query and add a limit and/or offset
|
||||||
fn limit(&self, sql: &str, limit: Option<usize>, offset: Option<usize>) -> String {
|
fn limit(&self, sql: &str, limit: Option<usize>, offset: Option<usize>) -> String {
|
||||||
let mut sql = sql.to_string();
|
let mut sql = sql.to_string();
|
||||||
|
@ -3,16 +3,42 @@
|
|||||||
//! Use of this driver requires enabling the `mysql` feature.
|
//! Use of this driver requires enabling the `mysql` feature.
|
||||||
//!
|
//!
|
||||||
//! Contains database-specific query data
|
//! Contains database-specific query data
|
||||||
|
//! Uses the [Mysql](https://crates.io/crates/mysql) crate for
|
||||||
|
//! interfacing with the database
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use std::any::Any;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use my::{Pool};
|
||||||
|
|
||||||
/// The struct implementing the `DatabaseDriver` trait
|
/// The struct implementing the `DatabaseDriver` trait
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MySQLDriver;
|
pub struct MySQLDriver {
|
||||||
|
connection: RefCell<Option<Pool>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl MySQLDriver {
|
impl MySQLDriver {
|
||||||
/// Create a MySQLDriver driver
|
/// Create a MySQLDriver driver
|
||||||
pub fn new() -> Self {
|
pub fn new(dsn: &str) -> Self {
|
||||||
MySQLDriver {}
|
let mut driver = MySQLDriver {
|
||||||
|
connection: RefCell::new(None)
|
||||||
|
};
|
||||||
|
|
||||||
|
driver.connect(dsn);
|
||||||
|
|
||||||
|
driver
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_new() -> Self {
|
||||||
|
MySQLDriver {
|
||||||
|
connection: RefCell::new(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connect(&mut self, dsn: &str) {
|
||||||
|
let connection = Pool::new(dsn).unwrap();
|
||||||
|
|
||||||
|
self.connection = RefCell::new(Some(connection));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,6 +49,10 @@ impl DatabaseDriver for MySQLDriver {
|
|||||||
('`', '`')
|
('`', '`')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn query(&self, sql: &str) -> Result<Box<dyn Any>, Box<dyn Any>> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
fn limit(&self, sql: &str, limit: Option<usize>, offset: Option<usize>) -> String {
|
fn limit(&self, sql: &str, limit: Option<usize>, offset: Option<usize>) -> String {
|
||||||
if limit.is_none() {
|
if limit.is_none() {
|
||||||
return sql.to_string();
|
return sql.to_string();
|
||||||
@ -44,10 +74,6 @@ impl DatabaseDriver for MySQLDriver {
|
|||||||
fn random(&self) -> String {
|
fn random(&self) -> String {
|
||||||
String::from(" RAND() DESC")
|
String::from(" RAND() DESC")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query(&self, sql: &str) -> Result<Box<dyn Any>, Box<dyn Any>> {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -56,7 +82,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_identifier_backtick_quote() {
|
fn test_quote_identifier_backtick_quote() {
|
||||||
let driver = MySQLDriver::new();
|
let driver = MySQLDriver::test_new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
driver.quote_identifier("foo, bar, baz"),
|
driver.quote_identifier("foo, bar, baz"),
|
||||||
@ -70,7 +96,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_identifiers_backtick_quote() {
|
fn test_quote_identifiers_backtick_quote() {
|
||||||
let driver = MySQLDriver::new();
|
let driver = MySQLDriver::test_new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
driver.quote_identifiers(vec![
|
driver.quote_identifiers(vec![
|
||||||
|
@ -36,14 +36,6 @@ impl PostgresDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DatabaseDriver for PostgresDriver {
|
impl DatabaseDriver for PostgresDriver {
|
||||||
fn explain(&self, sql: &str) -> String {
|
|
||||||
format!("EXPLAIN VERBOSE {}", sql)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn random(&self) -> String {
|
|
||||||
String::from(" RANDOM()")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query(&self, sql: &str) -> Result<Box<dyn Any>, Box<dyn Any>> {
|
fn query(&self, sql: &str) -> Result<Box<dyn Any>, Box<dyn Any>> {
|
||||||
if self.connection.borrow().is_none() {
|
if self.connection.borrow().is_none() {
|
||||||
panic!("No database connection.");
|
panic!("No database connection.");
|
||||||
@ -61,4 +53,12 @@ impl DatabaseDriver for PostgresDriver {
|
|||||||
Err(e) => Err(Box::new(e)),
|
Err(e) => Err(Box::new(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn explain(&self, sql: &str) -> String {
|
||||||
|
format!("EXPLAIN VERBOSE {}", sql)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random(&self) -> String {
|
||||||
|
String::from(" RANDOM()")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use slite::NO_PARAMS;
|
use slite::NO_PARAMS;
|
||||||
use slite::{params, Connection, Result};
|
use slite::{params, Connection, Result as SResult};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
/// The struct implementing the `DatabaseDriver` trait
|
/// The struct implementing the `DatabaseDriver` trait
|
||||||
@ -40,14 +40,6 @@ impl SQLiteDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DatabaseDriver for SQLiteDriver {
|
impl DatabaseDriver for SQLiteDriver {
|
||||||
fn explain(&self, sql: &str) -> String {
|
|
||||||
format!("EXPLAIN QUERY PLAN {}", sql)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn random(&self) -> String {
|
|
||||||
String::from(" RANDOM()")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query(&self, sql: &str) -> Result<Box<dyn Any>, Box<dyn Any>> {
|
fn query(&self, sql: &str) -> Result<Box<dyn Any>, Box<dyn Any>> {
|
||||||
if self.connection.borrow().is_none() {
|
if self.connection.borrow().is_none() {
|
||||||
panic!("No database connection.");
|
panic!("No database connection.");
|
||||||
@ -62,4 +54,18 @@ impl DatabaseDriver for SQLiteDriver {
|
|||||||
// TODO: map native result to generic result
|
// TODO: map native result to generic result
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the sql to empty a table
|
||||||
|
fn truncate(&self, table: &str) -> String {
|
||||||
|
String::from("DELETE FROM ")
|
||||||
|
+ &self.quote_identifier(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn explain(&self, sql: &str) -> String {
|
||||||
|
format!("EXPLAIN QUERY PLAN {}", sql)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random(&self) -> String {
|
||||||
|
String::from(" RANDOM()")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ pub fn split_map_join<'a>(
|
|||||||
.join(split_join_by)
|
.join(split_join_by)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_typed_ref<'a, T: 'static>(val: &'a Any) -> Option<&'a T> {
|
pub fn get_typed_ref<T: 'static>(val: &Any) -> Option<&T> {
|
||||||
if ! val.is::<T>() {
|
if ! val.is::<T>() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -32,7 +32,7 @@ pub fn get_typed_ref<'a, T: 'static>(val: &'a Any) -> Option<&'a T> {
|
|||||||
val.downcast_ref::<T>()
|
val.downcast_ref::<T>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_typed_mut<'a, T: 'static>(val: &'a mut Any) -> Option<&'a mut T> {
|
pub fn get_typed_mut<T: 'static>(val: &mut Any) -> Option<&mut T> {
|
||||||
if ! val.is::<T>() {
|
if ! val.is::<T>() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
30
src/lib.rs
30
src/lib.rs
@ -2,19 +2,31 @@
|
|||||||
//!
|
//!
|
||||||
//! A query builder using mostly strings, with methods following common SQL syntax
|
//! A query builder using mostly strings, with methods following common SQL syntax
|
||||||
//!
|
//!
|
||||||
//!
|
|
||||||
//! ```no_run
|
|
||||||
//! use stringqb::prelude::*;
|
|
||||||
//!
|
|
||||||
//! // Create a QueryBuilder object, with the chosen database driver
|
|
||||||
//! let mut qb = QueryBuilder::new(PostgresDriver::new("postgresql://user@localhost"));
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Drivers include:
|
//! Drivers include:
|
||||||
//! * `PostgresDriver` - for PostgreSQL databases
|
//! * `PostgresDriver` - for PostgreSQL databases
|
||||||
//! * `MySQLDriver` - for MySQL/MariaDB databases
|
//! * `MySQLDriver` - for MySQL/MariaDB databases
|
||||||
//! * `SQLiteDriver` - for SQLite databases
|
//! * `SQLiteDriver` - for SQLite databases
|
||||||
|
//!
|
||||||
|
//! Example:
|
||||||
|
//! ```no_run
|
||||||
|
//! use stringqb::prelude::*;
|
||||||
|
//!
|
||||||
|
//! // Create the database driver object (Postgres is enabled by default)
|
||||||
|
//! let pgDriver = PostgresDriver::new("postgres://user:pass@host:port/database");
|
||||||
|
//!
|
||||||
|
//! // The query builder must be mutable to be useful
|
||||||
|
//! let mut qb = QueryBuilder::new(pgDriver);
|
||||||
|
//!
|
||||||
|
//! // Each builder method returns a mutable reference to itself so
|
||||||
|
//! // the methods are chainable
|
||||||
|
//! qb.select("field as f")
|
||||||
|
//! .from("table t")
|
||||||
|
//! .inner_join("table_two tt", "field2 as ff", "=", "f")
|
||||||
|
//! .wher("f >", 3);
|
||||||
|
//!
|
||||||
|
//! // Since they are references, you do not have to chain.
|
||||||
|
//! let sql = qb.get_compiled_select();
|
||||||
|
//! ```
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -137,13 +137,16 @@ impl QueryBuilder {
|
|||||||
/// use stringqb::prelude::*;
|
/// use stringqb::prelude::*;
|
||||||
///
|
///
|
||||||
/// // Postgres Driver (If enabled)
|
/// // Postgres Driver (If enabled)
|
||||||
/// let pgDriver = PostgresDriver::new("postgres://");
|
/// let pgDriver = PostgresDriver::new("postgres://user:pass@host:port/database");
|
||||||
///
|
///
|
||||||
/// // SQLite Driver (memory)
|
/// // MySQL/MariaDB Driver, requires "mysql" feature
|
||||||
|
/// let myDriver = MySQLDriver::new("mysql://user:pass@host:port/database");
|
||||||
|
///
|
||||||
|
/// // SQLite Driver (memory), requires "sqlite" feature
|
||||||
/// #[cfg(feature = "sqlite")]
|
/// #[cfg(feature = "sqlite")]
|
||||||
/// let liteMemoryDriver = SQLiteDriver::new(":memory:");
|
/// let liteMemoryDriver = SQLiteDriver::new(":memory:");
|
||||||
///
|
///
|
||||||
/// // SQLite Driver (file)
|
/// // SQLite Driver (file), requires "sqlite" feature
|
||||||
/// #[cfg(feature = "sqlite")]
|
/// #[cfg(feature = "sqlite")]
|
||||||
/// let liteDriver = SQLiteDriver::new("/path/to/db.sqlite3");
|
/// let liteDriver = SQLiteDriver::new("/path/to/db.sqlite3");
|
||||||
///
|
///
|
||||||
@ -740,6 +743,19 @@ impl QueryBuilder {
|
|||||||
self.run(&sql)
|
self.run(&sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Empty the table of all values
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # use stringqb::prelude::*;
|
||||||
|
/// # let mut qb = QueryBuilder::default();
|
||||||
|
/// let query = qb.truncate("table");
|
||||||
|
/// ```
|
||||||
|
pub fn truncate(&mut self, table: &str) -> Result<Box<dyn Any>, Box<dyn Any>> {
|
||||||
|
let sql = self.driver.truncate(table);
|
||||||
|
|
||||||
|
self.basic_query(&sql)
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// ! SQL Returning Methods
|
// ! SQL Returning Methods
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
@ -757,16 +773,34 @@ impl QueryBuilder {
|
|||||||
|
|
||||||
/// Get the generated SQL for an insert query
|
/// Get the generated SQL for an insert query
|
||||||
pub fn get_compiled_insert(&self, table: &str) -> String {
|
pub fn get_compiled_insert(&self, table: &str) -> String {
|
||||||
|
// The fields and values to insert must be specified
|
||||||
|
assert!(
|
||||||
|
self.state.get_set_array_keys().len() > 0,
|
||||||
|
"You must use the `set` or `set_map` method to set columns and values to insert"
|
||||||
|
);
|
||||||
|
|
||||||
self.compile(QueryType::Insert, table)
|
self.compile(QueryType::Insert, table)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the generated SQL for an update query
|
/// Get the generated SQL for an update query
|
||||||
pub fn get_compiled_update(&self, table: &str) -> String {
|
pub fn get_compiled_update(&self, table: &str) -> String {
|
||||||
|
// Updates require fields and values
|
||||||
|
assert!(
|
||||||
|
self.state.get_set_array_keys().len() > 0,
|
||||||
|
"You must use the `set` or `set_map` method to set columns and values to update"
|
||||||
|
);
|
||||||
|
|
||||||
self.compile(QueryType::Update, table)
|
self.compile(QueryType::Update, table)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the generated SQL for a delete query
|
/// Get the generated SQL for a delete query
|
||||||
pub fn get_compiled_delete(&self, table: &str) -> String {
|
pub fn get_compiled_delete(&self, table: &str) -> String {
|
||||||
|
// Where clause required
|
||||||
|
assert!(
|
||||||
|
self.state.has_where_clause(),
|
||||||
|
"You must specify a where clause for delete. To empty a table, use the `truncate` method."
|
||||||
|
);
|
||||||
|
|
||||||
self.compile(QueryType::Delete, table)
|
self.compile(QueryType::Delete, table)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -989,8 +1023,6 @@ impl QueryBuilder {
|
|||||||
.append_query_map(QueryClauseType::Where, &conj, &item);
|
.append_query_map(QueryClauseType::Where, &conj, &item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn compile(&self, query_type: QueryType, table: &str) -> String {
|
fn compile(&self, query_type: QueryType, table: &str) -> String {
|
||||||
// Get the base clause for the query
|
// Get the base clause for the query
|
||||||
let base_sql = self.compile_type(query_type, &self.driver.quote_identifier(table));
|
let base_sql = self.compile_type(query_type, &self.driver.quote_identifier(table));
|
||||||
|
Loading…
Reference in New Issue
Block a user