use dao::{Type, ToType};
use table::{Table, Column};
use std::collections::BTreeMap;
use database::Database;
use dao::DaoResult;
use dao::IsDao;
use dao::Dao;
use table::IsTable;
use writer::SqlFrag;
#[derive(Debug)]
#[derive(Clone)]
pub enum JoinType{
CROSS,
INNER,
OUTER,
}
#[derive(Debug)]
#[derive(Clone)]
pub enum Modifier{
LEFT,
RIGHT,
FULL,
}
#[derive(Debug)]
#[derive(Clone)]
pub struct Join{
pub modifier:Option<Modifier>,
pub join_type:JoinType,
pub table_name:TableName,
pub column1:Vec<String>,
pub column2:Vec<String>
}
#[derive(Debug)]
#[derive(Clone)]
pub enum Direction{
ASC,
DESC,
}
#[derive(Debug)]
#[derive(Clone)]
pub enum Connector{
And,
Or
}
#[derive(Debug)]
#[derive(Clone)]
pub enum Equality{
EQ, NE, LT, LTE, GT, GTE, IN,
NOTIN, LIKE,
NULL,
NOTNULL, ISNULL,}
#[derive(Debug)]
#[derive(Clone)]
pub struct Function{
pub function:String,
pub params:Vec<Operand>,
}
#[derive(Debug)]
#[derive(Clone)]
pub enum Operand{
ColumnName(ColumnName),
TableName(TableName),
Function(Function),
Query(Query),
Value(Type),
Vec(Vec<Operand>),
}
#[derive(Debug)]
#[derive(Clone)]
pub struct Condition{
pub left_operand:Operand,
pub equality:Equality,
pub right_operand:Operand,
}
#[derive(Debug)]
#[derive(Clone)]
pub struct Filter{
pub connector:Connector,
pub condition: Condition,
pub subfilters:Vec<Filter>
}
impl Filter{
pub fn new(column:&str, equality:Equality, value:&ToType)->Self{
let right_operand = Operand::Value(value.to_db_type());
Filter{
connector:Connector::And,
condition: Condition{left_operand:
Operand::ColumnName(ColumnName::from_str(column)),
equality:equality,
right_operand:right_operand},
subfilters:vec![],
}
}
pub fn and(&mut self, column:&str, equality:Equality, value:&ToType)->&mut Self{
let mut filter = Filter::new(column, equality, value);
filter.connector = Connector::And;
self.subfilters.push(filter);
self
}
pub fn or(&mut self, column:&str, equality:Equality, value:&ToType)->&mut Self{
let mut filter = Filter::new(column, equality, value);
filter.connector = Connector::Or;
self.subfilters.push(filter);
self
}
}
#[derive(Debug)]
#[derive(Clone)]
pub enum SqlType{
SELECT,
INSERT,
UPDATE,
DELETE,
}
#[derive(Clone)]
#[derive(Debug)]
pub struct ColumnName{
pub column:String,
pub table:Option<String>,
pub schema:Option<String>,
pub rename:Option<String>
}
#[derive(Debug)]
#[derive(Clone)]
pub struct Field{
pub operand:Operand,
pub name:Option<String>,
}
impl ColumnName{
fn from_column(column:&Column, table:&Table)->Self{
ColumnName{
column: column.name.to_string(),
table: Some(table.name.to_string()),
schema: Some(table.schema.to_string()),
rename: None,
}
}
fn from_str(column:&str)->Self{
if column.contains("."){
let splinters = column.split(".").collect::<Vec<&str>>();
assert!(splinters.len() == 2, "There should only be 2 splinters");
let table_split = splinters[0].to_string();
let column_split = splinters[1].to_string();
ColumnName{
column:column_split.to_string(),
table:Some(table_split.to_string()),
schema:None,
rename:None
}
} else {
ColumnName{
column:column.to_string(),
table:None,
schema:None,
rename:None
}
}
}
fn rename(&self)->String{
return format!("{}_{}", self.table.as_ref().unwrap(), self.column)
}
pub fn complete_name(&self)->String{
if self.table.is_some(){
return format!("{}.{}", self.table.as_ref().unwrap(), self.column);
}else{
return self.column.to_string();
}
}
pub fn super_complete_name(&self)->String{
if self.schema.is_some(){
return format!("{}.{}", self.schema.as_ref().unwrap(), self.complete_name());
}else{
return self.complete_name();
}
}
}
impl PartialEq for ColumnName{
fn eq(&self, other: &Self) -> bool{
self.column == other.column
}
fn ne(&self, other: &Self) -> bool {
self.column != other.column
}
}
#[derive(Clone)]
#[derive(Debug)]
pub struct TableName{
pub schema: String,
pub name: String,
pub column_names: Vec<ColumnName>,
}
impl TableName{
fn from_table(table:&Table)->Self{
TableName{
schema:table.schema.to_string(),
name: table.name.to_string(),
column_names:vec![],
}
}
pub fn complete_name(&self)->String{
format!("{}.{}",self.schema, self.name)
}
}
impl PartialEq for TableName{
fn eq(&self, other: &Self) -> bool{
self.name == other.name && self.schema == other.schema
}
fn ne(&self, other: &Self) -> bool {
self.name != other.name || self.schema != other.schema
}
}
#[derive(Debug)]
#[derive(Clone)]
pub struct Query{
pub sql_type:SqlType,
pub distinct:bool,
pub declared_query: BTreeMap<String, Query>,
pub enumerated_fields:Vec<Field>,
pub renamed_columns:BTreeMap<String, Vec<(String, String)>>,
pub distinct_on_columns:Vec<String>,
pub filters:Vec<Filter>,
pub joins:Vec<Join>,
pub order_by:Vec<(String, Direction)>,
pub group_by: Vec<Operand>,
pub having: Vec<Condition>,
pub excluded_columns:Vec<ColumnName>,
pub page:Option<usize>,
pub page_size:Option<usize>,
pub from:Option<Box<Field>>,
pub values:Vec<Operand>,
pub enumerated_returns: Vec<Field>,
}
impl Query{
pub fn new()->Self{
Query{
sql_type:SqlType::SELECT,
distinct:false,
declared_query: BTreeMap::new(),
enumerated_fields: vec![],
renamed_columns:BTreeMap::new(),
distinct_on_columns: vec![],
filters: vec![],
joins: vec![],
order_by: vec![],
group_by: vec![],
having: vec![],
excluded_columns:vec![],
page:None,
page_size:None,
from: None,
values:vec![],
enumerated_returns: vec![],
}
}
pub fn select()->Self{
let mut q = Query::new();
q.sql_type = SqlType::SELECT;
q
}
pub fn insert()->Self{
let mut q = Query::new();
q.sql_type = SqlType::INSERT;
q
}
pub fn update()->Self{
let mut q = Query::new();
q.sql_type = SqlType::UPDATE;
q
}
pub fn delete()->Self{
let mut q = Query::new();
q.sql_type = SqlType::DELETE;
q
}
pub fn set_distinct(&mut self)->&mut Self{
self.distinct = true;
self
}
pub fn select_all(&mut self)->&mut Self{
self.enumerate_column("*")
}
pub fn enumerate_column(&mut self, column:&str)->&mut Self{
let column_name = ColumnName::from_str(column);
let operand = Operand::ColumnName(column_name);
let field = Field{operand:operand, name:None};
self.enumerated_fields.push(field);
self
}
pub fn enumerate_columns(&mut self, columns:Vec<&str>)->&mut Self{
for c in columns{
self.enumerate_column(c);
}
self
}
pub fn group_by(&mut self, columns:Vec<&str>)->&mut Self{
for c in columns{
let column_name = ColumnName::from_str(c);
let operand = Operand::ColumnName(column_name);
self.group_by.push(operand);
}
self
}
pub fn having(&mut self, column:&str, equality: Equality, value :&ToType)->&mut Self{
let column_name = ColumnName::from_str(column);
let left_operand = Operand::ColumnName(column_name);
let cond = Condition{
left_operand: left_operand,
equality: equality,
right_operand: Operand::Value(value.to_db_type())
};
self.having.push(cond);
self
}
pub fn enumerate(&mut self, columns:Vec<&str>)->&mut Self{
self.enumerate_columns(columns)
}
pub fn exclude_column(&mut self, column:&str)->&mut Self{
let c = ColumnName::from_str(column);
self.excluded_columns.push(c);
self
}
pub fn exclude_columns(&mut self, columns:Vec<&str>)->&mut Self{
for c in columns{
self.exclude_column(c);
}
self
}
pub fn distinct_on_columns(&mut self, columns:&Vec<String>)->&mut Self{
let columns = columns.clone();
for c in columns{
self.distinct_on_columns.push(c);
}
self
}
pub fn set_page(&mut self, page:usize)->&mut Self{
self.page = Some(page);
self
}
pub fn set_page_size(&mut self, items:usize)->&mut Self{
self.page_size = Some(items);
self
}
pub fn limit(&mut self, limit:usize)->&mut Self{
self.set_page_size(limit)
}
pub fn from_table(&mut self, table:&Table)->&mut Self{
let table_name = TableName::from_table(table);
let operand = Operand::TableName(table_name);
let field = Field{ operand:operand, name: None};
self.from_field(field)
}
pub fn from<T: IsTable>(&mut self)->&mut Self{
self.from_table(&T::table())
}
pub fn into_table(&mut self, table:&Table)->&mut Self{
self.sql_type = SqlType::INSERT;
self.from_table(table)
}
pub fn into<T:IsTable>(&mut self)->&mut Self{
self.into_table(&T::table())
}
pub fn declare_query(&mut self, query:Query, alias:&str)->&mut Self{
self.declared_query.insert(alias.to_string(), query);
self
}
pub fn from_query(&mut self, query:Query, alias:&str)->&mut Self{
let operand = Operand::Query(query);
let field = Field{operand:operand, name:Some(alias.to_string())};
self.from_field(field)
}
pub fn from_field(&mut self, field:Field)->&mut Self{
self.from = Some(Box::new(field));
self
}
pub fn get_from_table(&self)->Option<&TableName>{
match self.from{
Some(ref field) => {
match field.operand{
Operand::TableName(ref table_name) => {
Some(table_name)
},
_ => None
}
},
None => None,
}
}
pub fn enumerate_table_all_columns(&mut self, table: &Table)->&mut Self{
for c in &table.columns{
let column_name = ColumnName::from_column(c, table);
let operand = Operand::ColumnName(column_name);
let field = Field{operand:operand, name:None};
self.enumerated_fields.push(field);
}
self
}
pub fn join(&mut self, join:Join)->&mut Self{
self.joins.push(join);
self
}
pub fn left_join(&mut self, table:&Table, column1:&str, column2:&str)->&mut Self{
let join = Join{
modifier:Some(Modifier::LEFT),
join_type:JoinType::OUTER,
table_name: TableName::from_table(table),
column1:vec![column1.to_string()],
column2:vec![column2.to_string()]
};
self.join(join)
}
pub fn right_join(&mut self, table:&Table, column1:&str, column2:&str)->&mut Self{
let join = Join{
modifier:Some(Modifier::RIGHT),
join_type:JoinType::OUTER,
table_name: TableName::from_table(table),
column1:vec![column1.to_string()],
column2:vec![column2.to_string()]
};
self.join(join)
}
pub fn full_join(&mut self, table:&Table, column1:&str, column2:&str)->&mut Self{
let join = Join{
modifier:Some(Modifier::FULL),
join_type:JoinType::OUTER,
table_name: TableName::from_table(table),
column1:vec![column1.to_string()],
column2:vec![column2.to_string()]
};
self.join(join)
}
pub fn inner_join(&mut self, table:&Table, column1:&str, column2:&str)->&mut Self{
let join = Join{
modifier:None,
join_type:JoinType::INNER,
table_name: TableName::from_table(table),
column1:vec![column1.to_string()],
column2:vec![column2.to_string()]
};
self.join(join)
}
pub fn asc(&mut self, column:&str)->&mut Self{
self.order_by.push((column.to_string(), Direction::ASC));
self
}
pub fn desc(&mut self, column:&str)->&mut Self{
self.order_by.push((column.to_string(), Direction::DESC));
self
}
pub fn rename(&mut self, table:&str, column:&str, new_column_name:&str)->&mut Self{
if self.renamed_columns.get(table).is_some(){
let mut list:&mut Vec<(String, String)> = self.renamed_columns.get_mut(table).unwrap();
if list.contains(&(column.to_string(), new_column_name.to_string())){
println!("This is already renamed");
}else{
println!("renamed {} to {}", column, new_column_name);
list.push((column.to_string(), new_column_name.to_string()));
}
}
else{
self.renamed_columns.insert(table.to_string(), vec![(column.to_string(), new_column_name.to_string())]);
}
self
}
pub fn get_involved_tables(&self)->Vec<&TableName>{
let mut tables = vec![];
let from_table = self.get_from_table();
if from_table.is_some(){
tables.push(from_table.unwrap());
}
for j in &self.joins{
if !tables.contains(&&j.table_name){
tables.push(&j.table_name);
}
}
tables
}
pub fn finalize(&mut self)->&mut Self{
if self.excluded_columns.is_empty()
&& self.enumerated_fields.is_empty(){
self.select_all();
}
let excluded_columns = &self.excluded_columns.clone();
for i in excluded_columns{
self.remove_from_enumerated(&i);
}
self
}
fn remove_from_enumerated(&mut self, column_name: &ColumnName)->&mut Self{
fn index_of(enumerated_fields:&Vec<Field>, column: &ColumnName)->Option<usize>{
let mut cnt = 0;
for field in enumerated_fields{
match field.operand{
Operand::ColumnName(ref column_name) => {
if column_name == column{
return Some(cnt);
}
},
_ => {},
}
cnt += 1;
}
None
}
let index = index_of(&self.enumerated_fields, column_name);
if index.is_some(){
self.enumerated_fields.remove(index.unwrap());
}
self
}
pub fn get_enumerated_columns(&self)->Vec<&ColumnName>{
let mut columns = vec![];
for field in &self.enumerated_fields{
match field.operand{
Operand::ColumnName(ref column_name) => {
columns.push(column_name);
},
_ => {},
}
}
columns
}
pub fn add_filter(&mut self, filter:Filter)->&mut Self{
self.filters.push(filter);
self
}
pub fn filter(&mut self, column:&str, equality:Equality, value:&ToType)->&mut Self{
self.add_filter(Filter::new(column, equality, value))
}
pub fn add_value(&mut self, value:Operand)->&mut Self{
self.values.push(value);
self
}
pub fn value(&mut self, value:&ToType)->&mut Self{
let operand = Operand::Value(value.to_db_type());
self.add_value(operand)
}
pub fn enumerate_all_table_column_as_return(&mut self, table:&Table)->&mut Self{
for c in &table.columns{
let column_name = ColumnName::from_column(c, table);
let operand = Operand::ColumnName(column_name);
let field = Field{operand: operand, name:None};
self.enumerated_returns.push(field);
}
self
}
pub fn returns(&mut self, columns: Vec<&str>)->&mut Self{
for c in columns{
self.enumerate_column_as_return(c);
}
self
}
pub fn enumerate_column_as_return(&mut self, column:&str)->&mut Self{
let column_name = ColumnName::from_str(column);
let operand = Operand::ColumnName(column_name);
let field = Field{operand: operand, name:None};
self.enumerated_returns.push(field);
self
}
pub fn build(&self, db: &Database)->SqlFrag{
db.build_query(self)
}
fn execute_with_return(&mut self, db: &Database)->DaoResult{
self.finalize();
db.execute_with_return(self)
}
pub fn execute_with_one_return(&mut self, db: &Database)->Dao{
self.finalize();
db.execute_with_one_return(self)
}
pub fn execute(&mut self, db: &Database)->Result<usize, String>{
self.finalize();
db.execute(self)
}
pub fn collect<T: IsDao>(&mut self, db: &Database)->Vec<T>{
let result = self.execute_with_return(db);
T::from_dao_result(&result)
}
pub fn collect_one<T: IsDao>(&mut self, db: &Database)->T{
if self.page_size.is_none(){
self.limit(1);
}
let result = self.execute_with_return(db);
let mut dao:Vec<T> = T::from_dao_result(&result);
assert!(dao.len() == 1, "There should only be 1 returned record");
dao.remove(0)
}
}