Ugly progress commit

This commit is contained in:
Timothy Warren 2019-04-10 14:03:28 -04:00
parent b16cb8b8e4
commit 1776233a93
8 changed files with 61 additions and 34 deletions

View File

@ -30,6 +30,7 @@ struct QueryResult;
pub struct DefaultDriver; pub struct DefaultDriver;
impl DefaultDriver { impl DefaultDriver {
/// Create a `DefaultDriver`
pub fn new() -> Self { pub fn new() -> Self {
DefaultDriver {} DefaultDriver {}
} }
@ -61,7 +62,7 @@ pub trait DatabaseDriver: fmt::Debug {
/// 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 mut identifier = &mut String::from(identifier); let 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
@ -78,13 +79,12 @@ pub trait DatabaseDriver: fmt::Debug {
let trimmed_tiers = split_map_join(identifier, ".", |tier| { let trimmed_tiers = split_map_join(identifier, ".", |tier| {
let tier = tier.trim(); let tier = tier.trim();
// Here where the quoting actually happens. Everything
// else is breaking down the identifier list for this.
if tier.starts_with(open_char) && tier.ends_with(close_char) { if tier.starts_with(open_char) && tier.ends_with(close_char) {
return tier.to_string(); return tier.to_string();
} }
// Here where the quoting actually happens. Everything
// else is breaking down the identifier list for this.
format!("{}{}{}", &open_char, tier, &close_char) format!("{}{}{}", &open_char, tier, &close_char)
}); });

View File

@ -8,6 +8,7 @@ use super::*;
pub struct MSSQL; pub struct MSSQL;
impl MSSQL { impl MSSQL {
/// Create a MSSQL Driver
pub fn new() -> Self { pub fn new() -> Self {
MSSQL {} MSSQL {}
} }

View File

@ -8,6 +8,7 @@ use super::*;
pub struct MySQL; pub struct MySQL;
impl MySQL { impl MySQL {
/// Create a MySQL driver
pub fn new() -> Self { pub fn new() -> Self {
MySQL {} MySQL {}
} }

View File

@ -8,6 +8,7 @@ use super::*;
pub struct Postgres; pub struct Postgres;
impl Postgres { impl Postgres {
/// Create a Postgres driver
pub fn new() -> Self { pub fn new() -> Self {
Postgres {} Postgres {}
} }

View File

@ -8,6 +8,7 @@ use super::*;
pub struct SQLite; pub struct SQLite;
impl SQLite { impl SQLite {
/// Create an SQLite driver
pub fn new() -> Self { pub fn new() -> Self {
SQLite {} SQLite {}
} }

View File

@ -1,11 +1,11 @@
//! # StringQB //! # StringQB
//! //!
//! A query builder using mostly strings, with methods following common SQL syntax //! A query builder using mostly strings, with methods following common SQL syntax
// #![warn(missing_docs)] #![warn(missing_docs)]
#![allow(dead_code)]
pub mod drivers; pub mod drivers;
pub mod query_builder; pub mod query_builder;
pub mod types;
/// Split a string, apply a closure to each substring, /// Split a string, apply a closure to each substring,
/// then join the string back together /// then join the string back together

View File

@ -1,7 +1,7 @@
//! This main file is just for temparary testing //! This main file is just for temparary testing
use stringqb::drivers::postgres::Postgres; use stringqb::drivers::postgres::Postgres;
use stringqb::query_builder::QueryBuilder; use stringqb::query_builder::QueryBuilder;
use stringqb::types::{SQLType, Type}; // use stringqb::types::{SQLType, Type};
fn main() { fn main() {
let mut qb = QueryBuilder::new(Postgres::new()); let mut qb = QueryBuilder::new(Postgres::new());
@ -17,6 +17,6 @@ fn main() {
println!("QueryBuilder object: {:#?}", &qb); println!("QueryBuilder object: {:#?}", &qb);
println!("SQLType mapping: {:#?}", SQLType::SmallInt(32)); // println!("SQLType mapping: {:#?}", SQLType::SmallInt(32));
println!("Type: {:#?}", Type(Box::new(1234567890))); // println!("Type: {:#?}", Type(Box::new(1234567890)));
} }

View File

@ -5,6 +5,7 @@ use std::any::Any;
use std::collections::HashMap; use std::collections::HashMap;
use crate::drivers::{DatabaseDriver, DefaultDriver}; use crate::drivers::{DatabaseDriver, DefaultDriver};
use crate::split_map_join;
/// The position of the wildcard(s) /// The position of the wildcard(s)
/// for a `like` clause /// for a `like` clause
@ -26,18 +27,16 @@ pub enum LikeWildcard {
/// The type of SQL join /// The type of SQL join
#[derive(Debug)] #[derive(Debug)]
pub enum JoinType { pub enum JoinType {
/// A `CROSS` join
Cross,
/// An `INNER` join /// An `INNER` join
Inner, Inner,
/// An `OUTER` join /// An `OUTER` join
Outer, Outer,
/// A `LEFT` join /// A `LEFT (OUTER)` join
Left, Left,
/// A `RIGHT` join /// A `RIGHT (OUTER)` join
Right, Right,
/// A `LEFT OUTER` join
LeftOuter,
/// A `RIGHT OUTER` join
RightOuter,
} }
/// The sort direction /// The sort direction
@ -47,7 +46,7 @@ pub enum OrderDirection {
Asc, Asc,
/// Sort Descending /// Sort Descending
Desc, Desc,
/// Random Sort /// Random Sort (Not yet implemented!)
Rand, Rand,
} }
@ -61,6 +60,14 @@ enum QueryClauseType {
WhereIn, WhereIn,
} }
#[derive(Debug)]
enum QueryType {
Select,
Insert,
Update,
Delete,
}
#[derive(Debug)] #[derive(Debug)]
struct QueryClause { struct QueryClause {
clause_type: QueryClauseType, clause_type: QueryClauseType,
@ -197,7 +204,18 @@ impl QueryBuilder {
/// Set the fields to select from the database as a string /// Set the fields to select from the database as a string
pub fn select(&mut self, fields: &str) -> &mut Self { pub fn select(&mut self, fields: &str) -> &mut Self {
unimplemented!(); let fields = split_map_join(fields, ",", |s| s.trim().to_string());
// Split identifiers on `As` keyword so they can be quoted properly
// @TODO split identifiers on `as` keyword (needs to be case-insensitive)
// Quote the identifiers (where there was an `as` keyword)
// Rejoin those identifiers
self.state.append_select_string(&fields);
self
} }
/// Set the fields to select from the database as a Vector /// Set the fields to select from the database as a Vector
@ -284,7 +302,7 @@ impl QueryBuilder {
self self
} }
// Specify a condition for a `where` clause where a column has a value /// Specify a condition for a `where` clause where a column has a value
pub fn where_eq(&mut self, key: &str, value: Box<dyn Any>) -> &mut Self { pub fn where_eq(&mut self, key: &str, value: Box<dyn Any>) -> &mut Self {
self.r#where(key, "=", value) self.r#where(key, "=", value)
} }
@ -360,12 +378,11 @@ impl QueryBuilder {
let condition = table + " ON " + &col + op + value; let condition = table + " ON " + &col + op + value;
let join_type = match join_type { let join_type = match join_type {
JoinType::Cross => "CROSS ",
JoinType::Left => "LEFT ", JoinType::Left => "LEFT ",
JoinType::Inner => "INNER ", JoinType::Inner => "INNER ",
JoinType::LeftOuter => "LEFT OUTER ",
JoinType::Outer => "OUTER ", JoinType::Outer => "OUTER ",
JoinType::Right => "RIGHT ", JoinType::Right => "RIGHT ",
JoinType::RightOuter => "RIGHT OUTER",
}; };
let conjunction = "\n".to_string() + join_type + "JOIN "; let conjunction = "\n".to_string() + join_type + "JOIN ";
@ -438,26 +455,28 @@ 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 {
if self.state.query_map.len() == 0 { let conj = if self.state.query_map.len() == 0 {
self.state " WHERE "
.append_query_map(QueryClauseType::GroupStart, " ", "(");
} else { } else {
self.state " "
.append_query_map(QueryClauseType::GroupStart, " WHERE ", "("); };
}
self.state
.append_query_map(QueryClauseType::GroupStart, conj, "(");
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 {
if self.state.query_map.len() == 0 { let conj = if self.state.query_map.len() == 0 {
self.state " WHERE "
.append_query_map(QueryClauseType::GroupStart, " WHERE NOT ", "(");
} else { } else {
self.state " AND "
.append_query_map(QueryClauseType::GroupStart, " AND NOT ", "("); };
}
self.state
.append_query_map(QueryClauseType::GroupStart, conj, "NOT (");
self self
} }
@ -491,7 +510,7 @@ impl QueryBuilder {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/// Execute the built query /// Execute the built query
pub fn get(self) -> Box<dyn Any> { pub fn get(self) {
unimplemented!(); unimplemented!();
} }
@ -556,7 +575,11 @@ impl QueryBuilder {
// ! Implementation Details // ! Implementation Details
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
fn compile() -> String { fn compile(&self, query_type: QueryType, table: &str) -> String {
unimplemented!();
}
fn compile_type(&self, query_type: QueryType, table: &str) -> String {
unimplemented!(); unimplemented!();
} }
} }