Browse Source

Ugly progress commit

master
Timothy Warren 6 months ago
parent
commit
aad53f0f20
4 changed files with 158 additions and 12 deletions
  1. +2
    -2
      src/drivers.rs
  2. +14
    -1
      src/drivers/sqlite.rs
  3. +10
    -1
      src/lib.rs
  4. +132
    -8
      src/query_builder.rs

+ 2
- 2
src/drivers.rs View File

@@ -72,7 +72,7 @@ pub trait DatabaseDriver {
/// Quote the identifiers passed, so the database does not
/// normalize the identifiers (eg, table, column, etc.)
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,
// recurse to quote each identifier in the list
@@ -104,7 +104,7 @@ pub trait DatabaseDriver {
// Runs a basic sql query on the database
// 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<(), ()> {
Ok(())
}

+ 14
- 1
src/drivers/sqlite.rs View File

@@ -2,7 +2,8 @@
//!
//! 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 slite::NO_PARAMS;
@@ -36,6 +37,18 @@ impl SQLiteDriver {

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 {

+ 10
- 1
src/lib.rs View File

@@ -20,6 +20,10 @@
#[macro_use]
extern crate lazy_static;

#[cfg(feature = "sqlite")]
#[macro_use]
extern crate slite;

pub mod drivers;
pub mod fns;
pub mod query_builder;
@@ -31,7 +35,12 @@ pub mod prelude {
//! This includes enum types, traits,
//! the Query Builder, and individual database drivers.
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")]
/// Postgres Driver

+ 132
- 8
src/query_builder.rs View File

@@ -86,6 +86,11 @@ pub struct QueryBuilder {
driver: Box<dyn DatabaseDriver>,
}

/// The struct representing a prepared statement
pub struct Prepared {

}

impl Default for QueryBuilder {
/// Creates a new QueryBuilder instance with default driver
///
@@ -179,7 +184,7 @@ impl QueryBuilder {
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
pub fn explain(&mut self) -> &mut Self {
self.state.explain = true;
@@ -225,16 +230,55 @@ impl QueryBuilder {
}

/// 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 {
self._like(field, value, position, "LIKE", "OR")
}

/// 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 {
self._like(field, value, position, "NOT LIKE", "AND")
}

/// 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(
&mut self,
field: &str,
@@ -264,6 +308,16 @@ impl QueryBuilder {
}

/// 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 {
self._having(key, value, "OR")
}
@@ -294,16 +348,46 @@ impl QueryBuilder {

/// Alias method for `where`, as using the `where` method requires
/// 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 {
self.r#where(key, value)
self._where_string(key, value, "AND")
}

/// 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 {
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 {
self._where_in(key, values, "IN", "AND")
}
@@ -489,7 +573,17 @@ impl QueryBuilder {
// ! 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) {
let sql = self.get_compiled_select();

@@ -502,6 +596,15 @@ impl QueryBuilder {
}

/// 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) {
let sql = self.get_compiled_insert(table);

@@ -509,6 +612,16 @@ impl QueryBuilder {
}

/// 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) {
let sql = self.get_compiled_update(table);

@@ -563,8 +676,18 @@ impl QueryBuilder {
self
}

/// Execute an SQL query
pub fn query(&mut self, sql: &str) {
/// Execute an SQL query with no parameters
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!();
}

@@ -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![];
values.append(self.state.get_values());
values.append(self.state.get_where_values());

// @TODO determine query result type
// @TODO prepare/execute query, and return result
unimplemented!();
let stmt = self.prepare(sql);
self.execute(&stmt, values)
}
}


Loading…
Cancel
Save