Ugly progress commit

This commit is contained in:
Timothy Warren 2019-07-18 09:36:59 -04:00
parent f9569a6340
commit aad53f0f20
4 changed files with 158 additions and 12 deletions

View File

@ -72,7 +72,7 @@ pub trait DatabaseDriver {
/// Quote the identifiers passed, so the database does not /// Quote the identifiers passed, so the database does not
/// normalize the identifiers (eg, table, column, etc.) /// normalize the identifiers (eg, table, column, etc.)
fn quote_identifier(&self, identifier: &str) -> String { fn quote_identifier(&self, identifier: &str) -> String {
let identifier = &mut String::from(identifier); let mut identifier = &mut String::from(identifier);
// If the identifier is actually a comma-separated list, // If the identifier is actually a comma-separated list,
// recurse to quote each identifier in the list // recurse to quote each identifier in the list
@ -104,7 +104,7 @@ pub trait DatabaseDriver {
// Runs a basic sql query on the database // Runs a basic sql query on the database
// fn query(&self, sql: &str) -> Result<impl Any, impl Error>; // fn query(&self, sql: &str) -> Result<impl Any, impl Error>;
// Prepares an sql statement for the database /// Prepares an sql statement for the database
fn prepare(&self, sql: &str) -> Result<(), ()> { fn prepare(&self, sql: &str) -> Result<(), ()> {
Ok(()) Ok(())
} }

View File

@ -2,7 +2,8 @@
//! //!
//! Use of this driver requires enabling the `sqlite` feature. //! Use of this driver requires enabling the `sqlite` feature.
//! //!
//! Contains database-specific query data //! Uses the [rusqlite](https://crates.io/crates/rusqlite) crate for
//! interfacing with the database
use super::*; use super::*;
use slite::NO_PARAMS; use slite::NO_PARAMS;
@ -36,6 +37,18 @@ impl SQLiteDriver {
self.connection = RefCell::new(Some(connection)); self.connection = RefCell::new(Some(connection));
} }
pub fn query(&self, sql: &str) -> Result<usize> {
if self.connection.borrow().is_none() {
panic!("No database connection.");
}
self.connection
.borrow_mut()
.as_mut()
.unwrap()
.execute(sql, NO_PARAMS)
}
} }
impl DatabaseDriver for SQLiteDriver { impl DatabaseDriver for SQLiteDriver {

View File

@ -20,6 +20,10 @@
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
#[cfg(feature = "sqlite")]
#[macro_use]
extern crate slite;
pub mod drivers; pub mod drivers;
pub mod fns; pub mod fns;
pub mod query_builder; pub mod query_builder;
@ -31,7 +35,12 @@ pub mod prelude {
//! This includes enum types, traits, //! This includes enum types, traits,
//! the Query Builder, and individual database drivers. //! the Query Builder, and individual database drivers.
pub use crate::drivers::DatabaseDriver; pub use crate::drivers::DatabaseDriver;
pub use crate::query_builder::{JoinType, LikeWildcard, OrderDirection, QueryBuilder}; pub use crate::query_builder::{
JoinType,
LikeWildcard,
OrderDirection,
QueryBuilder,
};
#[cfg(feature = "postgres")] #[cfg(feature = "postgres")]
/// Postgres Driver /// Postgres Driver

View File

@ -86,6 +86,11 @@ pub struct QueryBuilder {
driver: Box<dyn DatabaseDriver>, driver: Box<dyn DatabaseDriver>,
} }
/// The struct representing a prepared statement
pub struct Prepared {
}
impl Default for QueryBuilder { impl Default for QueryBuilder {
/// Creates a new QueryBuilder instance with default driver /// Creates a new QueryBuilder instance with default driver
/// ///
@ -179,7 +184,7 @@ impl QueryBuilder {
self self
} }
/// Tell the database to give you query plain info, rather /// Tell the database to give you query plan info, rather
/// than a result set /// than a result set
pub fn explain(&mut self) -> &mut Self { pub fn explain(&mut self) -> &mut Self {
self.state.explain = true; self.state.explain = true;
@ -225,16 +230,55 @@ impl QueryBuilder {
} }
/// Generates an `or like` clause /// Generates an `or like` clause
///
/// ```no_run
/// # use stringqb::prelude::*;
/// # let mut qb = stringqb::query_builder::QueryBuilder::default();
/// // Search for a value that ends with "foo"
/// qb.or_like("field", String::from("foo"), LikeWildcard::Before);
///
/// // Search for a value that starts with "foo"
/// qb.or_like("field", String::from("foo"), LikeWildcard::After);
///
/// // Search for a value that has "foo" in it
/// qb.or_like("field", String::from("foo"), LikeWildcard::Both);
/// ```
pub fn or_like(&mut self, field: &str, value: impl Any, position: LikeWildcard) -> &mut Self { pub fn or_like(&mut self, field: &str, value: impl Any, position: LikeWildcard) -> &mut Self {
self._like(field, value, position, "LIKE", "OR") self._like(field, value, position, "LIKE", "OR")
} }
/// Generates a `not like` clause /// Generates a `not like` clause
///
/// ```no_run
/// # use stringqb::prelude::*;
/// # let mut qb = stringqb::query_builder::QueryBuilder::default();
/// // Search for a value that does not end with "foo"
/// qb.not_like("field", String::from("foo"), LikeWildcard::Before);
///
/// // Search for a value that does not start with "foo"
/// qb.not_like("field", String::from("foo"), LikeWildcard::After);
///
/// // Search for a value that does not have "foo" in it
/// qb.not_like("field", String::from("foo"), LikeWildcard::Both);
/// ```
pub fn not_like(&mut self, field: &str, value: impl Any, position: LikeWildcard) -> &mut Self { pub fn not_like(&mut self, field: &str, value: impl Any, position: LikeWildcard) -> &mut Self {
self._like(field, value, position, "NOT LIKE", "AND") self._like(field, value, position, "NOT LIKE", "AND")
} }
/// Generates an OR NOT Like clause /// Generates an OR NOT Like clause
///
/// ```no_run
/// # use stringqb::prelude::*;
/// # let mut qb = stringqb::query_builder::QueryBuilder::default();
/// // Search for a value that does not end with "foo"
/// qb.or_not_like("field", String::from("foo"), LikeWildcard::Before);
///
/// // Search for a value that does not start with "foo"
/// qb.or_not_like("field", String::from("foo"), LikeWildcard::After);
///
/// // Search for a value that does not have "foo" in it
/// qb.or_not_like("field", String::from("foo"), LikeWildcard::Both);
/// ```
pub fn or_not_like( pub fn or_not_like(
&mut self, &mut self,
field: &str, field: &str,
@ -264,6 +308,16 @@ impl QueryBuilder {
} }
/// Add a `having` clause to the query, prefixed with an `or` /// Add a `having` clause to the query, prefixed with an `or`
///
/// ```no_run
/// # use stringqb::prelude::*;
/// # let mut qb = QueryBuilder::default();
/// // By default, key = value
/// qb.or_having("key", vec!["value"]);
///
/// // Other operators can be used with a separating space
/// qb.or_having("clues <", vec![88]);
/// ```
pub fn or_having(&mut self, key: &str, value: Vec<impl Any>) -> &mut Self { pub fn or_having(&mut self, key: &str, value: Vec<impl Any>) -> &mut Self {
self._having(key, value, "OR") self._having(key, value, "OR")
} }
@ -294,16 +348,46 @@ impl QueryBuilder {
/// Alias method for `where`, as using the `where` method requires /// Alias method for `where`, as using the `where` method requires
/// using the raw identifier `r#where`. /// using the raw identifier `r#where`.
///
/// ```no_run
/// # use stringqb::prelude::*;
/// # let mut qb = QueryBuilder::default();
/// // By default, key = value
/// qb.wher("key", "value");
///
/// // Other operators can be used with a separating space
/// qb.wher("key >", 4);
/// ```
pub fn wher(&mut self, key: &str, value: impl Any) -> &mut Self { pub fn wher(&mut self, key: &str, value: impl Any) -> &mut Self {
self.r#where(key, value) self._where_string(key, value, "AND")
} }
/// Specify a condition for the `where` clause of the query, prefixed with `or` /// Specify a condition for the `where` clause of the query, prefixed with `or`
///
/// By default does not have any query grouping.
///
/// ```no_run
/// # use stringqb::prelude::*;
/// # let mut qb = QueryBuilder::default();
/// // By default, key = value
/// qb.or_where("key", "value");
///
/// // Other operators can be used with a separating space
/// qb.or_where("key !=", "foo");
/// ```
pub fn or_where(&mut self, key: &str, value: impl Any) -> &mut Self { pub fn or_where(&mut self, key: &str, value: impl Any) -> &mut Self {
self._where_string(key, value, "OR") self._where_string(key, value, "OR")
} }
/// Specify a `where in` clause for the query /// Specify a `where in` clause for the query. If called multiple times,
/// will prefix the clause with `AND`
///
/// ```no_run
/// # use stringqb::prelude::*;
/// # let mut qb = QueryBuilder::default();
/// // Look for a set of rows matching the values passed
/// qb.where_in("key", vec![1,2,3]);
/// ```
pub fn where_in(&mut self, key: &str, values: Vec<impl Any>) -> &mut Self { pub fn where_in(&mut self, key: &str, values: Vec<impl Any>) -> &mut Self {
self._where_in(key, values, "IN", "AND") self._where_in(key, values, "IN", "AND")
} }
@ -489,7 +573,17 @@ impl QueryBuilder {
// ! Query execution methods // ! Query execution methods
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/// Execute the built query /// Execute the generated select query
///
/// ```no_run
/// # use stringqb::prelude::*;
/// # let mut qb = QueryBuilder::default();
/// // The get() method actually calls the driver to run
/// // the SQL query
/// let query = db.select_vec(vec!["foo", "bar"])
/// .from("table t")
/// .get();
/// ```
pub fn get(&mut self) { pub fn get(&mut self) {
let sql = self.get_compiled_select(); let sql = self.get_compiled_select();
@ -502,6 +596,15 @@ impl QueryBuilder {
} }
/// Execute the generated insert query /// Execute the generated insert query
///
/// ```no_run
/// # use stringqb::prelude::*;
/// # let mut qb = QueryBuilder::default();
/// // The insert() method actually calls the driver to run
/// // the SQL query
/// let query = db.set("foo", 3)
/// .insert("table");
/// ```
pub fn insert(&mut self, table: &str) { pub fn insert(&mut self, table: &str) {
let sql = self.get_compiled_insert(table); let sql = self.get_compiled_insert(table);
@ -509,6 +612,16 @@ impl QueryBuilder {
} }
/// Execute the generated update query /// Execute the generated update query
///
/// ```no_run
/// # use stringqb::prelude::*;
/// # let mut qb = QueryBuilder::default();
/// // The update() method actually calls the driver to run
/// // the SQL query
/// let query = db.set("foo", 3)
/// .wher("foo", 4)
/// .update("table");
/// ```
pub fn update(&mut self, table: &str) { pub fn update(&mut self, table: &str) {
let sql = self.get_compiled_update(table); let sql = self.get_compiled_update(table);
@ -563,8 +676,18 @@ impl QueryBuilder {
self self
} }
/// Execute an SQL query /// Execute an SQL query with no parameters
pub fn query(&mut self, sql: &str) { pub fn basic_query(&mut self, sql: &str) {
self.driver.query(sql)
}
/// Prepare an SQL query
pub fn prepare(&mut self, sql: &str) -> Prepared {
unimplemented!();
}
/// Execute a prepared statement
pub fn execute(&mut self, stmt: &Prepared, params: &[Box<dyn Any>]) {
unimplemented!(); unimplemented!();
} }
@ -762,14 +885,15 @@ impl QueryBuilder {
} }
} }
fn run(&mut self, _sql: &str) { fn run(&mut self, sql: &str) {
let mut values: Vec<Box<Any>> = vec![]; let mut values: Vec<Box<Any>> = vec![];
values.append(self.state.get_values()); values.append(self.state.get_values());
values.append(self.state.get_where_values()); values.append(self.state.get_where_values());
// @TODO determine query result type // @TODO determine query result type
// @TODO prepare/execute query, and return result // @TODO prepare/execute query, and return result
unimplemented!(); let stmt = self.prepare(sql);
self.execute(&stmt, values)
} }
} }