use dao::{Value, ToValue};
use table::{Table};
use std::collections::BTreeMap;
use database::Database;
use dao::DaoResult;
use dao::IsDao;
use dao::Dao;
use table::IsTable;
use writer::SqlFrag;
use std::fmt;
#[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,
NOT_IN, LIKE,
NULL,
IS_NOT_NULL, IS_NULL,}
#[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(Value),
Vec(Vec<Operand>),
}
#[derive(Debug)]
#[derive(Clone)]
pub struct Condition{
pub left:Operand,
pub equality:Equality,
pub right: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:&ToValue)->Self{
let right = Operand::Value(value.to_db_type());
Filter{
connector:Connector::And,
condition: Condition{left: Operand::ColumnName(ColumnName::from_str(column)),
equality:equality,
right:right},
subfilters:vec![],
}
}
pub fn bare_new(left: Operand, equality: Equality, right: Operand)->Self{
Filter{
connector:Connector::And,
condition: Condition{left:left,
equality:equality,
right:right},
subfilters:vec![],
}
}
pub fn is_null(column:&str)->Self{
Filter::new(column, Equality::IS_NULL, &())
}
pub fn is_not_null(column:&str)->Self{
Filter::new(column, Equality::IS_NOT_NULL, &())
}
pub fn and(&mut self, column:&str, equality:Equality, value:&ToValue)->&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:&ToValue)->&mut Self{
let mut filter = Filter::new(column, equality, value);
filter.connector = Connector::Or;
self.subfilters.push(filter);
self
}
pub fn or_filter(&mut self, filter: Filter)->&mut Self{
let mut filter = filter.clone();
filter.connector = Connector::Or;
self.subfilters.push(filter);
self
}
pub fn and_filter(&mut self, filter: Filter)->&mut Self{
let mut filter = filter.clone();
filter.connector = Connector::And;
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>,
}
#[derive(Debug)]
#[derive(Clone)]
pub struct Field{
pub operand:Operand,
pub name:Option<String>,
}
impl Field{
fn rename(&self)->Field{
match self.operand{
Operand::ColumnName(ref column_name) => {
let rename = column_name.default_rename();
Field{
operand:Operand::ColumnName(column_name.clone()),
name:Some(rename)
}
},
_ => panic!("not yet")
}
}
}
impl ColumnName{
pub 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,
}
} else {
ColumnName{
column:column.to_string(),
table:None,
schema:None,
}
}
}
fn default_rename(&self)->String{
if self.table.is_some(){
return format!("{}_{}", self.table.as_ref().unwrap(), self.column);
}else{
panic!("Unable to rename {} since table is not specified", 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();
}
}
fn is_conflicted(&self, other:&ColumnName)->bool{
self.column == other.column
}
}
impl fmt::Display for ColumnName{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.complete_name())
}
}
impl PartialEq for ColumnName{
fn eq(&self, other: &Self) -> bool{
self.column == other.column && self.table == other.table
}
fn ne(&self, other: &Self) -> bool {
self.column != other.column || self.table != other.table || self.schema != other.schema
}
}
#[derive(Clone)]
#[derive(Debug)]
pub struct TableName{
pub schema: Option<String>,
pub name: String,
pub columns: Vec<ColumnName>,
}
impl TableName{
fn from_str(str: &str)->Self{
if str.contains("."){
let splinters = str.split(".").collect::<Vec<&str>>();
assert!(splinters.len() == 2, "There should only be 2 splinters");
let schema_split = splinters[0].to_string();
let table_split = splinters[1].to_string();
TableName{
schema: Some(schema_split),
name: table_split,
columns: vec![],
}
} else {
TableName{
schema: None,
name: str.to_string(),
columns: vec![],
}
}
}
pub fn complete_name(&self)->String{
match self.schema{
Some (ref schema) => format!("{}.{}",schema, self.name),
None => self.name.to_string()
}
}
}
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
}
}
impl fmt::Display for TableName{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.complete_name())
}
}
pub trait ToTableName{
fn to_table_name(&self)->TableName;
}
impl <'a>ToTableName for &'a str{
fn to_table_name(&self)->TableName{
TableName::from_str(self)
}
}
impl ToTableName for Table{
fn to_table_name(&self)->TableName{
let mut columns = vec![];
for c in &self.columns{
let column_name = ColumnName{
schema: Some(self.schema.to_string()),
table: Some(self.name.to_string()),
column: c.name.to_string(),
};
columns.push(column_name);
}
TableName{
schema:Some(self.schema.to_string()),
name: self.name.to_string(),
columns: columns,
}
}
}
pub enum Error{
NoTableSpecified(String),
NoColumnSpecified(String),
SqlError(String),
}
#[derive(Debug)]
#[derive(Clone)]
pub struct Query{
pub sql_type:SqlType,
pub distinct: bool,
pub enumerate_all: bool,
pub declared_query: BTreeMap<String, Query>,
pub enumerated_fields:Vec<Field>,
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,
enumerate_all: false,
declared_query: BTreeMap::new(),
enumerated_fields: vec![],
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 distinct(&mut self)->&mut Self{
self.distinct = true;
self
}
pub fn select_all()->Self{
let mut q = Self::select();
q.all();
q
}
pub fn enumerate_all()->Self{
let mut q = Self::select();
q.enumerate_all = true;
q
}
pub fn all(&mut self)->&mut Self{
self.column("*")
}
fn enumerate(&mut self, column_name: ColumnName)->&mut Self{
let operand = Operand::ColumnName(column_name);
let field = Field{operand:operand, name:None};
self.enumerated_fields.push(field);
self
}
pub fn column(&mut self, column:&str)->&mut Self{
let column_name = ColumnName::from_str(column);
self.enumerate(column_name);
self
}
pub fn columns(&mut self, columns:Vec<&str>)->&mut Self{
for c in columns{
self.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 :&ToValue)->&mut Self{
let column_name = ColumnName::from_str(column);
let left = Operand::ColumnName(column_name);
let cond = Condition{
left: left,
equality: equality,
right: Operand::Value(value.to_db_type())
};
self.having.push(cond);
self
}
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(&mut self, table: &ToTableName)->&mut Self{
let table_name = table.to_table_name();
let operand = Operand::TableName(table_name);
let field = Field{ operand:operand, name: None};
self.from_field(field)
}
pub fn from_table(&mut self, table:&str)->&mut Self{
self.from(&table)
}
pub fn into_(&mut self, table :&ToTableName)->&mut Self{
self.sql_type = SqlType::INSERT;
self.from(table)
}
pub fn into_table(&mut self, table: &str)->&mut Self{
self.into_(&table)
}
pub fn table(&mut self, table: &ToTableName)->&mut Self{
self.from(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 join(&mut self, join:Join)->&mut Self{
self.joins.push(join);
self
}
pub fn left_join_table(&mut self, table:&str, column1:&str, column2:&str)->&mut Self{
self.left_join(&table, column1, column2)
}
pub fn left_join(&mut self, table:&ToTableName, column1:&str, column2:&str)->&mut Self{
let join = Join{
modifier:Some(Modifier::LEFT),
join_type:JoinType::OUTER,
table_name: table.to_table_name(),
column1:vec![column1.to_string()],
column2:vec![column2.to_string()]
};
self.join(join)
}
pub fn right_join_table(&mut self, table:&str, column1:&str, column2:&str)->&mut Self{
self.right_join(&table, column1, column2)
}
pub fn right_join(&mut self, table:&ToTableName, column1:&str, column2:&str)->&mut Self{
let join = Join{
modifier:Some(Modifier::RIGHT),
join_type:JoinType::OUTER,
table_name: table.to_table_name(),
column1:vec![column1.to_string()],
column2:vec![column2.to_string()]
};
self.join(join)
}
pub fn full_join_table(&mut self, table:&str, column1:&str, column2:&str)->&mut Self{
self.full_join(&table, column1, column2)
}
pub fn full_join(&mut self, table:&ToTableName, column1:&str, column2:&str)->&mut Self{
let join = Join{
modifier:Some(Modifier::FULL),
join_type:JoinType::OUTER,
table_name: table.to_table_name(),
column1:vec![column1.to_string()],
column2:vec![column2.to_string()]
};
self.join(join)
}
pub fn inner_join_table(&mut self, table:&str, column1:&str, column2:&str)->&mut Self{
self.inner_join(&table, column1, column2)
}
pub fn inner_join(&mut self, table:&ToTableName, column1:&str, column2:&str)->&mut Self{
let join = Join{
modifier:None,
join_type:JoinType::INNER,
table_name: table.to_table_name(),
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
}
fn match_fields_indexes(&self, column: &str)->Vec<usize>{
let mut indexes = vec![];
let mut cnt = 0;
for field in &self.enumerated_fields{
match field.operand{
Operand::ColumnName(ref column_name) => {
if column_name.column == column{
indexes.push(cnt);
}
},
_ => {},
}
cnt += 1;
}
indexes
}
fn rename_fields(&mut self, column:&str)->&mut Self{
let matched_indexes = self.match_fields_indexes(column);
for index in matched_indexes{
let field = self.enumerated_fields.remove(index); let field = field.rename(); self.enumerated_fields.insert(index, field); }
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().clone());
}
for j in &self.joins{
if !tables.contains(&&j.table_name){
tables.push(j.table_name.clone());
}
}
tables
}
pub fn finalize(&mut self)->&Self{
let involved_models = self.get_involved_tables();
if involved_models.len() > 1{
if self.enumerate_all{
self.enumerate_involved_tables_columns(&involved_models);
}
self.rename_conflicting_columns(); }
let excluded_columns = &self.excluded_columns.clone();
for i in excluded_columns{
self.remove_from_enumerated(&i);
}
if self.excluded_columns.is_empty()
&& self.enumerated_fields.is_empty(){
self.all();
}
self
}
fn enumerate_involved_tables_columns(&mut self, involved_models:&Vec<TableName>){
for m in involved_models{
for c in &m.columns{
self.enumerate(c.clone());
}
}
}
fn get_renamed_fields(&self)->Vec<&Field>{
let mut renamed = vec![];
for field in &self.enumerated_fields{
if field.name.is_some(){
renamed.push(field);
}
}
renamed
}
pub fn get_renamed_columns(&self)->Vec<(ColumnName, String)>{
let mut renamed_columns = vec![];
let renamed_fields = self.get_renamed_fields();
for field in &renamed_fields{
match field.operand{
Operand::ColumnName(ref column_name) => {
if field.name.is_some(){
let rename = field.name.as_ref().unwrap().to_string();
renamed_columns.push( (column_name.clone(), rename ) );
}
},
_ => ()
}
}
renamed_columns
}
fn get_conflicting_columns(&self)->Vec<String>{
let mut conflicts = vec![];
let enumerated_columns = self.get_enumerated_columns();
for c in &enumerated_columns{
for d in &enumerated_columns{
if c != d {
if c.is_conflicted(d){
conflicts.push(c.column.to_string());
}
}
}
}
conflicts
}
fn rename_conflicting_columns(&mut self)->&mut Self{
let conflicts = self.get_conflicting_columns();
for c in conflicts{
self.rename_fields(&c);
}
self
}
fn index_of_field(&self, column: &ColumnName)->Option<usize>{
let mut cnt = 0;
for field in &self.enumerated_fields{
match field.operand{
Operand::ColumnName(ref column_name) => {
if column_name == column{
return Some(cnt);
}
},
_ => {},
}
cnt += 1;
}
None
}
fn remove_from_enumerated(&mut self, column_name: &ColumnName)->&mut Self{
let index = self.index_of_field(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:&ToValue)->&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:&ToValue)->&mut Self{
let operand = Operand::Value(value.to_db_type());
self.add_value(operand)
}
pub fn set(&mut self, column: &str, value:&ToValue)->&mut Self{
self.column(column);
self.value(value)
}
pub fn return_all(&mut self)->&mut Self{
self.enumerate_column_as_return("*")
}
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(&mut self, db: &mut Database)->SqlFrag{
self.finalize();
db.build_query(self)
}
pub fn execute_with_return(&mut self, db: &mut Database)->DaoResult{
self.finalize();
db.execute_with_return(self)
}
pub fn execute_with_one_return(&mut self, db: &mut Database)->Dao{
self.finalize();
db.execute_with_one_return(self)
}
pub fn execute(&mut self, db: &mut Database)->Result<usize, String>{
self.finalize();
db.execute(self)
}
pub fn collect<T: IsDao+IsTable>(&mut self, db: &mut Database)->Vec<T>{
let result = self.execute_with_return(db);
result.cast()
}
pub fn collect_one<T: IsDao+IsTable>(&mut self, db: &mut Database)->Option<T>{
let result = self.execute_with_return(db);
result.cast_one()
}
}