From 861069abe70e0e7314e0fb22ee1d1fe6667f6ea1 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Mon, 22 Apr 2019 08:59:40 -0400 Subject: [PATCH] prgress commit --- Cargo.toml | 3 +-- src/drivers.rs | 10 ++++++--- src/drivers/mysql.rs | 2 ++ src/drivers/postgres.rs | 43 ++++++++++++++++++++++++++++++++++----- src/lib.rs | 10 ++++++++- src/query_builder.rs | 19 ++++++++--------- tests/integration_test.rs | 3 +-- 7 files changed, 67 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4cd096a..eb710c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,7 @@ regex = "1.1.5" serde_json = "1.0.39" [dependencies.pg] -version="0.15.2" -features=["with-serde_json"] +version="0.16.0-rc.1" optional=true package="postgres" diff --git a/src/drivers.rs b/src/drivers.rs index d1c6129..3271267 100644 --- a/src/drivers.rs +++ b/src/drivers.rs @@ -3,7 +3,8 @@ //! Drivers represent a connection to a specific type of database engine use crate::fns::split_map_join; use regex::Regex; -use std::fmt; +use std::any::Any; +use std::error::Error; #[cfg(feature = "postgres")] pub mod postgres; @@ -50,7 +51,7 @@ impl DatabaseDriver for DefaultDriver { /// Database Driver Trait /// /// Interface between the database connection library and the query builder -pub trait DatabaseDriver: fmt::Debug { +pub trait DatabaseDriver { /// Get which characters are used to delimit identifiers /// such as tables, and columns fn _quotes(&self) -> (char, char) { @@ -103,7 +104,10 @@ pub trait DatabaseDriver: fmt::Debug { } // Runs a basic sql query on the database - // fn query(&self, query: &str) -> Result<(), ()>; + // fn query(&self, sql: &str) -> Result; + + // Runs a prepared statement on the database + // fn execute(&self, sql: &str, ?) -> Result // ------------------------------------------------------------------------ // ! Driver-specific SQL methods diff --git a/src/drivers/mysql.rs b/src/drivers/mysql.rs index 1850c3c..70bbe27 100644 --- a/src/drivers/mysql.rs +++ b/src/drivers/mysql.rs @@ -1,5 +1,7 @@ //! Database Driver for MySQL //! +//! Use of this driver requires enabling the `mysql` feature. +//! //! Contains database-specific query data use super::*; diff --git a/src/drivers/postgres.rs b/src/drivers/postgres.rs index 5f9ceef..77a3ce3 100644 --- a/src/drivers/postgres.rs +++ b/src/drivers/postgres.rs @@ -1,16 +1,49 @@ //! Database Driver for Postgres //! -//! Contains database-specific query data +//! Use of this driver requires enabling the `postgres` feature. The `postgres` +//! feature is enabled by default. +//! +//! Uses the [Postgres](https://crates.io/crates/postgres) crate for +//! interfacing with the database use super::*; +use pg::{Client, Error, NoTls, Row}; +use std::any::Any; +use std::cell::RefCell; + /// The struct implementing the `DatabaseDriver` trait -#[derive(Debug)] -pub struct PostgresDriver; +pub struct PostgresDriver { + connection: RefCell>, +} impl PostgresDriver { /// Create a PostgresDriver driver - pub fn new() -> Self { - PostgresDriver {} + pub fn new(dsn: &str) -> Self { + let mut driver = PostgresDriver { + connection: RefCell::new(None), + }; + + driver.connect(dsn); + + driver + } + + fn connect(&mut self, dsn: &str) { + let connection = Client::connect(dsn, NoTls).unwrap(); + + self.connection = RefCell::new(Some(connection)); + } + + pub fn query(&self, sql: &str) -> Result, Error> { + if self.connection.borrow().is_none() { + panic!("No database connection."); + } + + self.connection + .borrow_mut() + .as_mut() + .unwrap() + .query(sql, &[]) } } diff --git a/src/lib.rs b/src/lib.rs index d3f3ede..8dfef52 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,11 +2,19 @@ //! //! 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 qb = QueryBuilder::new(PostgresDriver::new("postgresql://user@localhost")); //! //! ``` +//! +//! Drivers include: +//! * `PostgresDriver` - for PostgreSQL databases +//! * `MySQLDriver` - for MySQL/MariaDB databases +//! * `SQLiteDriver` - for SQLite databases #![warn(missing_docs)] #[macro_use] diff --git a/src/query_builder.rs b/src/query_builder.rs index 9d505d9..b535bcd 100644 --- a/src/query_builder.rs +++ b/src/query_builder.rs @@ -80,7 +80,6 @@ enum QueryType { } /// The struct representing a query builder -#[derive(Debug)] pub struct QueryBuilder { /// The struct to store the query builder info state: QueryState, @@ -207,7 +206,7 @@ impl QueryBuilder { // ! 'Like' methods // -------------------------------------------------------------------------- - /// Creates a `like` clause in the sql statement + /// Creates a `like` clause in the sql /// /// ```no_run /// # use stringqb::prelude::*; @@ -225,12 +224,12 @@ impl QueryBuilder { self._like(field, value, position, "LIKE", "AND") } - /// Generates an OR Like clause + /// Generates an `or like` clause pub fn or_like(&mut self, field: &str, value: impl Any, position: LikeWildcard) -> &mut Self { self._like(field, value, position, "LIKE", "OR") } - /// Generates a NOI Like clause + /// Generates a `not like` clause pub fn not_like(&mut self, field: &str, value: impl Any, position: LikeWildcard) -> &mut Self { self._like(field, value, position, "NOT LIKE", "AND") } @@ -255,10 +254,10 @@ impl QueryBuilder { /// # use stringqb::prelude::*; /// # let mut qb = QueryBuilder::default(); /// // By default, key = value - /// qb.having("key", vec![Box::new("value")]); + /// qb.having("key", vec!["value"]); /// /// // Other operators can be used with a separating space - /// qb.having("clues >=", vec![Box::new(4)]); + /// qb.having("clues >=", vec![4]); /// ``` pub fn having(&mut self, key: &str, value: Vec) -> &mut Self { self._having(key, value, "AND") @@ -281,10 +280,10 @@ impl QueryBuilder { /// # use stringqb::prelude::*; /// # let mut qb = QueryBuilder::default(); /// // By default, key = value - /// qb.r#where("key", Box::new("value")); + /// qb.r#where("key", "value"); /// /// // Other operators can be used with a separating space - /// qb.r#where("key >", Box::new(4)); + /// qb.r#where("key >", 4); /// ``` pub fn r#where(&mut self, key: &str, value: impl Any) -> &mut Self { self._where_string(key, value, "AND") @@ -681,7 +680,7 @@ impl QueryBuilder { match last_item.clause_type { QueryClauseType::GroupStart => String::from(""), - _ => format!(" {} ", conj) + _ => format!(" {} ", conj), } } else { format!(" {} ", conj) @@ -939,7 +938,7 @@ impl QueryState { pub fn get_query_map_last(&self) -> Option<&QueryClause> { if self.query_map.len() == 0 { - return None + return None; } let index = self.query_map.len() - 1; diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 15892b5..33edec3 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -51,8 +51,7 @@ fn select_without_from() { fn select_where() { let mut qb = QueryBuilder::default(); - qb.from("test") - .r#where("foo", "bar"); + qb.from("test").r#where("foo", "bar"); let sql = qb.get_compiled_select(); let expected = "SELECT *\nFROM \"test\" WHERE \"foo\"=?";