Slight refactor, implement having methods

This commit is contained in:
Timothy Warren 2019-04-16 15:18:32 -04:00
parent f7efadeb66
commit 9183e2f475
3 changed files with 68 additions and 55 deletions

View File

@ -50,6 +50,8 @@ pub enum QueryClauseType {
GroupEnd, GroupEnd,
/// Starting a parenthetical grouping /// Starting a parenthetical grouping
GroupStart, GroupStart,
/// A having clause
Having,
/// A join clause /// A join clause
Join, Join,
/// A like clause /// A like clause

View File

@ -164,7 +164,7 @@ impl QueryBuilder {
/// Generates an OR Like clause /// Generates an OR Like clause
pub fn or_like(&mut self, field: &str, value: Box<dyn Any>, position: LikeWildcard) -> &mut Self { pub fn or_like(&mut self, field: &str, value: Box<dyn Any>, position: LikeWildcard) -> &mut Self {
self._like(field, Box::new(value), position, "LIKE", "OR") self._like(field, value, position, "LIKE", "OR")
} }
/// Generates a NOI Like clause /// Generates a NOI Like clause
@ -182,13 +182,13 @@ impl QueryBuilder {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/// Add a `having` clause to the query /// Add a `having` clause to the query
pub fn having(&mut self, key: &str, value: Box<dyn Any>) -> &mut Self { pub fn having(&mut self, key: &str, value: Vec<Box<dyn Any>>) -> &mut Self {
unimplemented!(); self._having(key, value, "AND")
} }
/// Add a `having` clause to the query, prefixed with an `or` /// Add a `having` clause to the query, prefixed with an `or`
pub fn or_having(&mut self, key: &str, value: Box<dyn Any>) -> &mut Self { pub fn or_having(&mut self, key: &str, value: Vec<Box<dyn Any>>) -> &mut Self {
unimplemented!(); self._having(key, value, "OR")
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -266,6 +266,13 @@ impl QueryBuilder {
} }
/// Add a table join to the query /// Add a table join to the query
///
/// ```no_run
/// # use stringqb::prelude::*;
/// # let mut qb = QueryBuilder::default();
/// // Note that the value is not escaped, due to it often being a column
/// qb.join("table1", "column1", "<>", "foo", JoinType::Inner);
/// ```
pub fn join( pub fn join(
&mut self, &mut self,
table: &str, table: &str,
@ -307,16 +314,11 @@ impl QueryBuilder {
/// Add an order by clause to the query /// Add an order by clause to the query
pub fn order_by(&mut self, field: &str, direction: OrderDirection) -> &mut Self { pub fn order_by(&mut self, field: &str, direction: OrderDirection) -> &mut Self {
if direction == OrderDirection::Rand {
// @TODO handle random sorting
unimplemented!();
}
let field = self.driver.quote_identifier(field); let field = self.driver.quote_identifier(field);
let dir = match direction { let dir = match direction {
OrderDirection::Asc => String::from("ASC"), OrderDirection::Asc => String::from("ASC"),
OrderDirection::Desc => String::from("DESC"), OrderDirection::Desc => String::from("DESC"),
OrderDirection::Rand => String::from("RAND"), OrderDirection::Rand => self.driver.random(),
}; };
self.state.append_order_map(&field, &dir); self.state.append_order_map(&field, &dir);
@ -327,11 +329,7 @@ impl QueryBuilder {
&order_clauses.push(clause); &order_clauses.push(clause);
} }
let order_str = if direction != OrderDirection::Rand { let order_str = "\nORDER BY ".to_string() + &order_clauses.join(", ");
"\nORDER BY ".to_string() + &order_clauses.join(", ")
} else {
unimplemented!();
};
self.state.set_order_string(&order_str); self.state.set_order_string(&order_str);
@ -358,28 +356,16 @@ impl QueryBuilder {
/// Start a logical grouping in the current query /// Start a logical grouping in the current query
pub fn group_start(&mut self) -> &mut Self { pub fn group_start(&mut self) -> &mut Self {
let conj = if self.state.query_map_empty() {
" WHERE "
} else {
" "
};
self.state self.state
.append_query_map(QueryClauseType::GroupStart, conj, "("); .append_query_map(QueryClauseType::GroupStart, " ", "(");
self self
} }
/// Start a logical grouping, prefixed with `not` /// Start a logical grouping, prefixed with `not`
pub fn not_group_start(&mut self) -> &mut Self { pub fn not_group_start(&mut self) -> &mut Self {
let conj = if self.state.query_map_empty() {
" WHERE "
} else {
" AND "
};
self.state self.state
.append_query_map(QueryClauseType::GroupStart, conj, "NOT ("); .append_query_map(QueryClauseType::GroupStart, " AND ", "NOT (");
self self
} }
@ -505,12 +491,6 @@ impl QueryBuilder {
LikeWildcard::Both => format!("%{}%", *string_val), LikeWildcard::Both => format!("%{}%", *string_val),
}; };
let conj = if self.state.query_map_empty() {
" WHERE "
} else {
conj
};
self.state self.state
.append_query_map(QueryClauseType::Like, conj, &like); .append_query_map(QueryClauseType::Like, conj, &like);
self.state.append_where_values(Box::new(value)); self.state.append_where_values(Box::new(value));
@ -518,10 +498,40 @@ impl QueryBuilder {
self self
} }
fn _where(&mut self, key: &str, values: Vec<Box<dyn Any>>) -> HashMap<String, Box<dyn Any>> { fn _having(&mut self, key: &str, values: Vec<Box<dyn Any>>, conj: &str) -> &mut Self {
let mut map: HashMap<String, Box<dyn Any>> = HashMap::new(); let keys = self._where(key, values);
unimplemented!(); for k in keys {
self._having_key(&k, conj);
}
self
}
fn _having_key(&mut self, key: &str, conj:&str) -> &mut Self {
let field = key.trim().split(" ").collect::<Vec<&str>>();
let mut item = self.driver.quote_identifier(field[0]);;
let item2 = if field.len() == 1 {
String::from("=?")
} else {
format!(" {} ?", &field[1])
};
item += &item2;
self.state.append_having_map(conj, &item);
self
}
fn _where(&mut self, key: &str, values: Vec<Box<dyn Any>>) -> Vec<String> {
for x in values {
self.state.append_where_values(x);
}
vec![String::from(key)]
} }
fn _where_in(&mut self, key: &str, values: Vec<Box<dyn Any>>, in_str: &str, conj: &str) -> &mut Self { fn _where_in(&mut self, key: &str, values: Vec<Box<dyn Any>>, in_str: &str, conj: &str) -> &mut Self {
@ -532,12 +542,6 @@ impl QueryBuilder {
self.state.append_where_values(value); self.state.append_where_values(value);
} }
let conj = if self.state.query_map_empty() {
" WHERE "
} else {
conj
};
let str = format!("{} {} ({}) ", key, in_str, placeholders.join(",")); let str = format!("{} {} ({}) ", key, in_str, placeholders.join(","));
self.state.append_query_map(QueryClauseType::WhereIn, conj, &str); self.state.append_query_map(QueryClauseType::WhereIn, conj, &str);

View File

@ -104,11 +104,20 @@ impl QueryState {
pub fn append_having_map( pub fn append_having_map(
&mut self, &mut self,
clause_type: QueryClauseType,
conj: &str, conj: &str,
s: &str, s: &str,
) -> &mut Self { ) -> &mut Self {
self.having_map.push(QueryClause::new(clause_type, conj, s)); let conj = if self.having_map.len() == 0 {
String::from(" HAVING ")
} else {
format!(" {} ", conj)
};
self.having_map.push(QueryClause::new(
QueryClauseType::Having,
&conj,
s
));
self self
} }
@ -143,6 +152,12 @@ impl QueryState {
conj: &str, conj: &str,
s: &str, s: &str,
) -> &mut Self { ) -> &mut Self {
let conj = if self.query_map.len() == 0 {
" WHERE "
} else {
conj
};
self.query_map.push(QueryClause::new(clause_type, conj, s)); self.query_map.push(QueryClause::new(clause_type, conj, s));
self self
@ -196,10 +211,6 @@ impl QueryState {
&self.where_values &self.where_values
} }
pub fn having_map_empty(&self) -> bool {
self.having_map.len() == 0
}
pub fn set_from_string(&mut self, s: &str) -> &mut Self { pub fn set_from_string(&mut self, s: &str) -> &mut Self {
self.from_string = String::from(s); self.from_string = String::from(s);
@ -217,8 +228,4 @@ impl QueryState {
self self
} }
pub fn query_map_empty(&self) -> bool {
self.query_map.len() == 0
}
} }