Yet another ugly progress commit
This commit is contained in:
parent
88bcd5f0fb
commit
7fd51aa76c
@ -21,6 +21,21 @@ struct QueryResult;
|
|||||||
///
|
///
|
||||||
/// Interface between the database connection library and the query builder
|
/// Interface between the database connection library and the query builder
|
||||||
pub trait DatabaseDriver: fmt::Debug {
|
pub trait DatabaseDriver: fmt::Debug {
|
||||||
|
/// Vector version of `quote_identifier`
|
||||||
|
fn quote_identifiers(&self, identifiers: Vec<String>) -> Vec<String> {
|
||||||
|
let mut output: Vec<String> = vec![];
|
||||||
|
|
||||||
|
for identifier in identifiers {
|
||||||
|
output.push(self.quote_identifier(&identifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Quote the identifiers passed, so the database does not
|
||||||
|
/// normalize the identifiers (eg, table, column, etc.)
|
||||||
|
fn quote_identifier(&self, identifier: &str) -> String;
|
||||||
|
|
||||||
/// Runs a basic sql query on the database
|
/// Runs a basic sql query on the database
|
||||||
fn query(&self, query: &str) -> Result<(), ()>;
|
fn query(&self, query: &str) -> Result<(), ()>;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use pg;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Postgres;
|
pub struct Postgres;
|
||||||
|
|
||||||
#[cfg(feature="pg")]
|
#[cfg(feature="pg")]
|
||||||
impl DatabaseDriver for Postgres {
|
impl DatabaseDriver for Postgres {
|
||||||
|
fn quote_identifier(&self, identifier: &str) -> String {
|
||||||
|
String::from(identifier)
|
||||||
|
}
|
||||||
|
|
||||||
fn query(&self, _query: &str) -> Result<(), ()> {
|
fn query(&self, _query: &str) -> Result<(), ()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct SQLite;
|
pub struct SQLite;
|
||||||
|
|
||||||
impl DatabaseDriver for SQLite {
|
impl DatabaseDriver for SQLite {
|
||||||
|
fn quote_identifier(&self, identifier: &str) -> String {
|
||||||
|
String::from(identifier)
|
||||||
|
}
|
||||||
|
|
||||||
fn query(&self, _query: &str) -> Result<(), ()> {
|
fn query(&self, _query: &str) -> Result<(), ()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -6,24 +6,40 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use crate::drivers::DatabaseDriver;
|
use crate::drivers::DatabaseDriver;
|
||||||
|
|
||||||
|
/// The position of the wildcard(s)
|
||||||
|
/// for a `like` clause
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LikeWildcard {
|
pub enum LikeWildcard {
|
||||||
|
/// Wildcard before search term
|
||||||
|
/// eg. `%foo`
|
||||||
Before,
|
Before,
|
||||||
|
|
||||||
|
/// Wildcard after the search term
|
||||||
|
/// eg. `foo%`
|
||||||
After,
|
After,
|
||||||
|
|
||||||
|
/// Wildcards surrounding the search term
|
||||||
|
/// eg. `%foo%`
|
||||||
Both,
|
Both,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The type of SQL join
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum JoinType {
|
pub enum JoinType {
|
||||||
Inner,
|
Inner,
|
||||||
Outer,
|
Outer,
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
|
LeftOuter,
|
||||||
|
RightOuter,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The sort direction
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum OrderDirection {
|
pub enum OrderDirection {
|
||||||
|
/// Sort Ascending
|
||||||
Asc,
|
Asc,
|
||||||
|
/// Sort Descending
|
||||||
Desc,
|
Desc,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +61,7 @@ struct QueryClause {
|
|||||||
string: String,
|
string: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Debug)]
|
||||||
struct QueryState {
|
struct QueryState {
|
||||||
select_string: String,
|
select_string: String,
|
||||||
from_string: String,
|
from_string: String,
|
||||||
@ -68,9 +84,9 @@ struct QueryState {
|
|||||||
// Values to apply to where clauses in prepared statements
|
// Values to apply to where clauses in prepared statements
|
||||||
where_values: Vec<Box<dyn Any>>,
|
where_values: Vec<Box<dyn Any>>,
|
||||||
|
|
||||||
limit: u32,
|
limit: Option<u32>,
|
||||||
|
|
||||||
offset: u32,
|
offset: Option<u32>,
|
||||||
|
|
||||||
// Query components for complex selects
|
// Query components for complex selects
|
||||||
query_map: Vec<QueryClause>,
|
query_map: Vec<QueryClause>,
|
||||||
@ -79,6 +95,30 @@ struct QueryState {
|
|||||||
having_map: Vec<QueryClause>,
|
having_map: Vec<QueryClause>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for QueryState {
|
||||||
|
fn default() -> Self {
|
||||||
|
QueryState {
|
||||||
|
select_string: String::from(""),
|
||||||
|
from_string: String::from(""),
|
||||||
|
set_string: String::from(""),
|
||||||
|
order_string: String::from(""),
|
||||||
|
group_string: String::from(""),
|
||||||
|
|
||||||
|
set_array_keys: vec![],
|
||||||
|
order_array: HashMap::new(),
|
||||||
|
group_array: HashMap::new(),
|
||||||
|
values: vec![],
|
||||||
|
where_values: vec![],
|
||||||
|
|
||||||
|
limit: None,
|
||||||
|
offset: None,
|
||||||
|
|
||||||
|
query_map: vec![],
|
||||||
|
having_map: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl QueryState {
|
impl QueryState {
|
||||||
pub fn new() -> QueryState {
|
pub fn new() -> QueryState {
|
||||||
QueryState::default()
|
QueryState::default()
|
||||||
@ -94,7 +134,7 @@ pub struct QueryBuilder {
|
|||||||
|
|
||||||
impl QueryBuilder {
|
impl QueryBuilder {
|
||||||
/// Creates a new QueryBuilder instance
|
/// Creates a new QueryBuilder instance
|
||||||
pub fn new() -> QueryBuilder {
|
pub fn new() -> Self {
|
||||||
QueryBuilder {
|
QueryBuilder {
|
||||||
state: QueryState::new(),
|
state: QueryState::new(),
|
||||||
driver: None,
|
driver: None,
|
||||||
@ -110,7 +150,7 @@ impl QueryBuilder {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds the 'distinct' keyword to a query
|
/// Adds the `distinct` keyword to a query
|
||||||
pub fn distinct(mut self) -> Self {
|
pub fn distinct(mut self) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
@ -127,22 +167,22 @@ impl QueryBuilder {
|
|||||||
// ! 'Like' methods
|
// ! 'Like' methods
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
// Creates a like clause in the sql statement
|
/// Creates a `like` clause in the sql statement
|
||||||
pub fn like(mut self, field: &str, value: Box<dyn Any>, position: LikeWildcard) -> Self {
|
pub fn like(mut self, field: &str, value: Box<dyn Any>, position: LikeWildcard) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates an OR Like clause
|
/// Generates an OR Like clause
|
||||||
pub fn or_like(mut self, field: &str, value: Box<dyn Any>, position: LikeWildcard) -> Self {
|
pub fn or_like(mut self, field: &str, value: Box<dyn Any>, position: LikeWildcard) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a NOI Like clause
|
/// Generates a NOI Like clause
|
||||||
pub fn not_like(mut self, field: &str, value: Box<dyn Any>, position: LikeWildcard) -> Self {
|
pub fn not_like(mut self, field: &str, value: Box<dyn Any>, position: LikeWildcard) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates an OR NOT Like clause
|
/// Generates an OR NOT Like clause
|
||||||
pub fn or_not_like(mut self, field: &str, value: Box<dyn Any>, position: LikeWildcard) -> Self {
|
pub fn or_not_like(mut self, field: &str, value: Box<dyn Any>, position: LikeWildcard) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
@ -151,10 +191,12 @@ impl QueryBuilder {
|
|||||||
// ! Having methods
|
// ! Having methods
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Add a `having` clause to the query
|
||||||
pub fn having(mut self, key:&str, value: Box<dyn Any>) -> Self {
|
pub fn having(mut self, key:&str, value: Box<dyn Any>) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a `having` clause to the query, prefixed with an `or`
|
||||||
pub fn or_having(mut self, key:&str, value: Box<dyn Any>) -> Self {
|
pub fn or_having(mut self, key:&str, value: Box<dyn Any>) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
@ -163,27 +205,32 @@ impl QueryBuilder {
|
|||||||
// ! 'Where' methods
|
// ! 'Where' methods
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Specify a condition for the where clause of the query
|
/// Specify a condition for the `where` clause of the query
|
||||||
pub fn r#where(mut self, key: &str, value: Box<dyn Any>) -> Self {
|
pub fn r#where(mut self, key: &str, value: Box<dyn Any>) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specify a condition for the `where` clause of the query, prefixed with `or`
|
||||||
pub fn or_where(mut self, key: &str, value: Box<dyn Any>) -> Self {
|
pub fn or_where(mut self, key: &str, value: Box<dyn Any>) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specify a `where in` clause for the query
|
||||||
pub fn where_in(mut self, key: &str, value: Vec<Box<dyn Any>>) -> Self {
|
pub fn where_in(mut self, key: &str, value: Vec<Box<dyn Any>>) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specify a `where in` clause for the query, prefixed with `or`
|
||||||
pub fn or_where_in(mut self, key: &str, value: Vec<Box<dyn Any>>) -> Self {
|
pub fn or_where_in(mut self, key: &str, value: Vec<Box<dyn Any>>) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specify a `where not in` clause for the query
|
||||||
pub fn where_not_in(mut self, key: &str, value: Vec<Box<dyn Any>>) -> Self {
|
pub fn where_not_in(mut self, key: &str, value: Vec<Box<dyn Any>>) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specify a `where not in` clause for the query, prefixed with `or`
|
||||||
pub fn or_where_not_in(mut self, key: &str, value: Vec<Box<dyn Any>>) -> Self {
|
pub fn or_where_not_in(mut self, key: &str, value: Vec<Box<dyn Any>>) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
@ -202,7 +249,7 @@ impl QueryBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set a map of data for an insert or update query
|
/// Set a map of data for an insert or update query
|
||||||
pub fn set_batch(mut self, data: HashMap<String, Box<dyn Any>>) -> Self {
|
pub fn set_map(mut self, data: HashMap<String, Box<dyn Any>>) -> Self {
|
||||||
for (key, value) in data {
|
for (key, value) in data {
|
||||||
self = self.set(&key, value);
|
self = self.set(&key, value);
|
||||||
}
|
}
|
||||||
@ -210,43 +257,60 @@ impl QueryBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a table join to the query
|
/// Add a table join to the query
|
||||||
pub fn join(mut self, table: &str, condition: &str, join_type: JoinType) -> Self {
|
pub fn join(mut self, table: &str, condition: &str, join_type: JoinType) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a group by clause to the query
|
||||||
pub fn group_by(mut self, field: &str) -> Self {
|
pub fn group_by(mut self, field: &str) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add an order by clause to the query
|
||||||
pub fn order_by(mut self, field: &str, direction: OrderDirection) -> Self {
|
pub fn order_by(mut self, field: &str, direction: OrderDirection) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn limit(mut self, limit: u32, offset: u32) -> Self {
|
/// Add a limit to the query
|
||||||
unimplemented!();
|
pub fn limit(mut self, limit: u32) -> Self {
|
||||||
|
self.state.limit = Some(limit);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an offset to the query
|
||||||
|
pub fn offset(mut self, offset: u32) -> Self {
|
||||||
|
self.state.offset = Some(offset);
|
||||||
|
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// ! Query Grouping Methods
|
// ! Query Grouping Methods
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Start a logical grouping in the current query
|
||||||
pub fn group_start(mut self) -> Self {
|
pub fn group_start(mut self) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Start a logical grouping, prefixed with `not`
|
||||||
pub fn not_group_start(mut self) -> Self {
|
pub fn not_group_start(mut self) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Start a logical grouping, prefixed with `or`
|
||||||
pub fn or_group_start(mut self) -> Self {
|
pub fn or_group_start(mut self) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Start a logical grouping, prefixed with `or not`
|
||||||
pub fn or_not_group_start(mut self) -> Self {
|
pub fn or_not_group_start(mut self) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// End the current logical grouping
|
||||||
pub fn group_end(mut self) -> Self {
|
pub fn group_end(mut self) -> Self {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
@ -260,21 +324,25 @@ impl QueryBuilder {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Count all the rows in the specified database table
|
||||||
pub fn count_all(self, table: &str) -> u32 {
|
pub fn count_all(self, table: &str) -> u32 {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute the generated insert query
|
||||||
pub fn insert(mut self, table: &str) {
|
pub fn insert(mut self, table: &str) {
|
||||||
// @TODO determine query result type
|
// @TODO determine query result type
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute the generated update query
|
||||||
pub fn update(mut self, table: &str) {
|
pub fn update(mut self, table: &str) {
|
||||||
// @TODO determine query result type
|
// @TODO determine query result type
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(mut self, table: &str, where_clause: &str) {
|
/// Execute the generated delete query
|
||||||
|
pub fn delete(mut self, table: &str) {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,18 +350,22 @@ impl QueryBuilder {
|
|||||||
// ! SQL Returning Methods
|
// ! SQL Returning Methods
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Get the generated SQL for a select query
|
||||||
pub fn get_compiled_select(self) -> String {
|
pub fn get_compiled_select(self) -> String {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the generated SQL for an insert query
|
||||||
pub fn get_compiled_insert(self) -> String {
|
pub fn get_compiled_insert(self) -> String {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the generated SQL for an update query
|
||||||
pub fn get_compiled_update(self) -> String {
|
pub fn get_compiled_update(self) -> String {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the generated SQL for a delete query
|
||||||
pub fn get_compiled_delete(self) -> String {
|
pub fn get_compiled_delete(self) -> String {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
@ -302,8 +374,9 @@ impl QueryBuilder {
|
|||||||
// ! Miscellaneous Methods
|
// ! Miscellaneous Methods
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Get a new instance of the query builder
|
||||||
pub fn reset_query(mut self) -> Self {
|
pub fn reset_query(mut self) -> Self {
|
||||||
unimplemented!();
|
QueryBuilder::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,24 +390,28 @@ mod tests {
|
|||||||
.set("foo", Box::new("bar"));
|
.set("foo", Box::new("bar"));
|
||||||
|
|
||||||
assert!(builder.state.values[0].is::<&str>());
|
assert!(builder.state.values[0].is::<&str>());
|
||||||
|
|
||||||
|
// @TODO find a way to make this kind of operation much more ergonomic
|
||||||
|
assert_eq!(*builder.state.values[0].downcast_ref::<&str>().unwrap(), "bar");
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn set_hashmap() {
|
#[test]
|
||||||
// let qb = QueryBuilder::new();
|
fn set_hashmap() {
|
||||||
//
|
let qb = QueryBuilder::new();
|
||||||
// let mut authors = HashMap::new();
|
|
||||||
// authors.insert(
|
let mut authors: HashMap<String, Box<dyn Any>> = HashMap::new();
|
||||||
// String::from("Chinua Achebe"),
|
authors.insert(
|
||||||
// Box::new("Nigeria"));
|
String::from("Chinua Achebe"),
|
||||||
// authors.insert(
|
Box::new(String::from("Nigeria")));
|
||||||
// String::from("Rabindranath Tagore"),
|
authors.insert(
|
||||||
// Box::new("India"));
|
String::from("Rabindranath Tagore"),
|
||||||
// authors.insert(
|
Box::new(String::from("India")));
|
||||||
// String::from("Anita Nair"),
|
authors.insert(
|
||||||
// Box::new("India"));
|
String::from("Anita Nair"),
|
||||||
//
|
Box::new(String::from("India")));
|
||||||
// let qb = qb.set_batch(authors);
|
|
||||||
//
|
let qb = qb.set_map(authors);
|
||||||
// assert_eq!(qb.state.values.len(), 3);
|
|
||||||
// }
|
assert_eq!(qb.state.values.len(), 3);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user