From 296e87e3e91e27dce55fc10e746a54081c3f07f8 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Tue, 16 Apr 2019 15:51:27 -0400 Subject: [PATCH] Implement the remaining query builder methods, except those that call the database --- src/enums.rs | 2 +- src/main.rs | 2 +- src/query_builder.rs | 83 ++++++++++++++++++++++++++------ src/query_builder/query_state.rs | 6 ++- 4 files changed, 75 insertions(+), 18 deletions(-) diff --git a/src/enums.rs b/src/enums.rs index 56b3860..b247697 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -44,7 +44,7 @@ pub enum OrderDirection { } /// The type of Query Clause -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum QueryClauseType { /// Ending a parenthetical grouping GroupEnd, diff --git a/src/main.rs b/src/main.rs index e71c976..7a81a54 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ fn main() { .set("buzz", Box::new((1, 2.0, true, 'q'))); // This just makes me sad - qb.r#where("foo", "<>", Box::new(2)); + qb.r#where("foo <>", Box::new(2)); println!("QueryBuilder object: {:#?}", &qb); diff --git a/src/query_builder.rs b/src/query_builder.rs index 45031c3..64e52a2 100644 --- a/src/query_builder.rs +++ b/src/query_builder.rs @@ -124,6 +124,14 @@ impl QueryBuilder { self } + /// Tell the database to give you query plain info, rather + /// than a result set + pub fn explain(&mut self) -> &mut Self { + self.state.explain = true; + + self + } + /// Specify the database table to select from /// /// ``` @@ -195,22 +203,31 @@ impl QueryBuilder { // ! 'Where' methods // -------------------------------------------------------------------------- - /// Specify a condition for the `where` clause of the query - pub fn r#where(&mut self, key: &str, op: &str, value: Box) -> &mut Self { - // @TODO actually implement setting the keys for the where - self.state.append_where_values(value); - - unimplemented!(); + /// Alias method for `r#where`. + pub fn filter(&mut self, key: &str, value: Box) -> &mut Self { + self.r#where(key, value) } - /// Specify a condition for a `where` clause where a column has a value - pub fn where_eq(&mut self, key: &str, value: Box) -> &mut Self { - self.r#where(key, "=", value) + /// Specify a condition for the `where` clause of the query. Can be called + /// multiple times, which will then add additional where conditions, prefixed + /// with 'AND'. + /// + /// ```no_run + /// # use stringqb::prelude::*; + /// # let mut qb = QueryBuilder::default(); + /// // By default, key = value + /// qb.r#where("key", Box::new("value")); + /// + /// // Other operators can be used with a separating space + /// qb.r#where("key >", Box::new(4)); + /// ``` + pub fn r#where(&mut self, key: &str, value: Box) -> &mut Self { + self._where_string(key, value, "AND") } /// Specify a condition for the `where` clause of the query, prefixed with `or` pub fn or_where(&mut self, key: &str, value: Box) -> &mut Self { - unimplemented!(); + self._where_string(key, value, "OR") } /// Specify a `where in` clause for the query @@ -549,8 +566,38 @@ impl QueryBuilder { self } - fn _where_string(&mut self, key: &str, value: Box) -> &mut Self { - unimplemented!(); + fn _where_string(&mut self, key: &str, value: Box, conj: &str) -> &mut Self { + let keys = self._where(key, vec![value]); + + for k in keys { + self._where_string_key(key, conj); + } + + self + } + + fn _where_string_key(&mut self, key: &str, conj: &str) { + let field = key.trim().split(" ").collect::>(); + let query_map = self.state.get_query_map(); + + let last_item = &query_map[query_map.len() - 1]; + let mut item = self.driver.quote_identifier(field[0]); + + let item2 = if field.len() == 1 { + String::from("=?") + } else { + format!(" {} ?", &field[1]) + }; + + item += &item2; + + let conj = if last_item.clause_type == QueryClauseType::GroupStart { + String::from("") + } else { + format!(" {} ", conj) + }; + + self.state.append_query_map(QueryClauseType::Where, &conj, &item); } fn compile(&self, query_type: QueryType, table: &str) -> String { @@ -570,11 +617,17 @@ impl QueryBuilder { &parts.push(clause.to_string()); } - let sql = parts.join(""); + let mut sql = parts.join(""); - // @TODO handle limit / offset + // Add limit/ offset + sql = self.driver.limit(&sql, self.state.limit, self.state.offset); - sql + // Handle explain + if self.state.explain == true { + self.driver.explain(&sql) + } else { + sql + } } fn compile_type(&self, query_type: QueryType, table: &str) -> String { diff --git a/src/query_builder/query_state.rs b/src/query_builder/query_state.rs index bd97dac..20bb086 100644 --- a/src/query_builder/query_state.rs +++ b/src/query_builder/query_state.rs @@ -2,7 +2,7 @@ use super::*; #[derive(Debug)] pub struct QueryClause { - clause_type: QueryClauseType, + pub clause_type: QueryClauseType, conjunction: String, string: String, } @@ -23,6 +23,8 @@ impl QueryClause { #[derive(Debug)] pub struct QueryState { + pub explain: bool, + select_string: String, from_string: String, set_string: String, @@ -58,6 +60,8 @@ pub struct QueryState { impl Default for QueryState { fn default() -> Self { QueryState { + explain: false, + select_string: String::from(""), from_string: String::from(""), set_string: String::from(""),