use std::collections::HashMap;
use utils::bind_variables;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
use walkdir::{ WalkDir};
use std::fs;
use model::{SqlMap};
use serde_xml_rs::from_reader;
use pgsql::connect_db;
use serde::{Serialize};
pub mod utils;
pub mod model;
pub mod pgsql;
pub mod oracle;
pub mod uodbc;
pub enum DB {
Oracle(String),
Posgresql(String),
}
#[derive(Debug)]
pub enum DbConnStatus {
Idle,
Active,
Disconnected,
}
#[derive(Debug, Serialize)]
pub enum Value {
String(String),
StringLikeLeft(String),
StringLikeRight(String),
StringLikeBoth(String),
Float(f64),
Integer(i64),
Bool(bool),
Date(String),
StringArray(Vec<String>),
IntegerArray(Vec<i64>),
BareString(String),
}
pub enum ColumnType {
String,
Float,
Integer,
Date,
}
pub struct Column {
pub name: String,
pub column_type: ColumnType,
}
pub struct SqlParam<'a> {
pub sql_id: &'a str,
pub sub_sql_id: &'a str,
pub param: &'a HashMap<String, Value>,
}
lazy_static! {
static ref SQL_CACHE: HashMap<String, String> = {
let mut map = HashMap::new();
let sql_path = "resources/sql";
WalkDir::new(sql_path)
.into_iter()
.filter_entry(|e| is_not_hidden(e))
.filter_map(|v| v.ok())
.for_each(|x|
if x.path().display().to_string().as_str().ends_with(".xml") || x.path().display().to_string().as_str().ends_with(".sql") {
let path = format!("{}", x.path().display());
let contents = fs::read_to_string(&path).expect("Something went wrong reading the file");
let sql_map: SqlMap = match from_reader(contents.as_bytes()) {
Ok(t) => t,
Err(e) => {
println!("Error on reading SQL files: {}", &e);
panic!("{:?}", e);
}
};
for sql in sql_map.sql_statements{
let sql_id = &sql.id;
let statement = &sql.statement;
map.insert(String::from(sql_id), String::from(statement));
for not_empty in sql.is_not_empty {
let sql_id2 = format!("{}.#isNotEmpty#.{}", sql_id, ¬_empty.property);
map.insert(String::from(sql_id2), String::from(¬_empty.statement));
}
for is_equal in sql.is_equal {
let sql_id2 = format!("{}.#isEqual#.{}.{}", sql_id, &is_equal.property, &is_equal.value);
map.insert(String::from(sql_id2), String::from(&is_equal.statement));
}
for clause in sql.clauses{
let sql_id2 = format!("{}.{}", sql_id, &clause.id);
map.insert(String::from(sql_id2), String::from( &clause.statement));
for not_empty in clause.is_not_empty {
let sql_id2 = format!("{}.{}.#isNotEmpty#.{}", sql_id, &clause.id, ¬_empty.property);
map.insert(String::from(sql_id2), String::from(¬_empty.statement));
}
for is_equal in clause.is_equal {
let sql_id2 = format!("{}.{}.#isEqual#.{}.{}", sql_id, &clause.id, &is_equal.property, &is_equal.value);
map.insert(String::from(sql_id2), String::from(&is_equal.statement));
}
}
if !sql.footer.is_empty() {
let sql_id2 = format!("{}.#footer#", sql_id);
map.insert(String::from(sql_id2), String::from(&sql.footer));
}
}
}
);
map
};
static ref DATA_TYPE_CACHE: HashMap<String, String> = {
let sql = build_sql("select_table_columns", "", &HashMap::new());
let map = match connect_db() {
Ok(mut conn) => {
let mut map : HashMap<String, String> = HashMap::new();
for row in conn.query(sql.as_str(), &[]).unwrap() {
let table_name : &str = row.get("table_name");
let column_name : &str = row.get("column_name");
let udt_name : &str = row.get("udt_name");
map.insert(format!("{}.{}", table_name, column_name), udt_name.to_string());
}
map
}
Err(e) => {
println!("DATA_TYPE_CACHE error: {}", e);
HashMap::new()
}
};
map
};
static ref DB_PROPERTIES: HashMap<String, String> = {
let filepath = "resources/application.properties";
let contents = fs::read_to_string(filepath).expect("Something went wrong reading the file");
let mut map = HashMap::new();
for line in contents.lines() {
if line.starts_with("//") || line.starts_with("#"){
continue;
}
let tokens: Vec<&str> = line.split("=").collect();
if tokens.len() >= 2 {
map.insert(String::from(tokens[0]), String::from(tokens[1]));
}
}
map
};
}
pub fn build_sql<'a>(sql_id : &'a str, sub_sql_id: &'a str, arg : &HashMap<String, Value>) -> String {
let mut sql = String::new();
if sub_sql_id.is_empty() {
sql = String::from(match SQL_CACHE.get(sql_id) {
Some(f) => f,
_ => panic!("No such SQL: {}", sql_id)
})
} else {
let sub_sql_id = format!("{}.{}", sql_id, sub_sql_id);
sql = match (SQL_CACHE.get(sql_id), SQL_CACHE.get(&sub_sql_id)) {
(Some(m), Some(n)) => {
format!("{}\n{}", m, n)
}
_ => panic!("No such SQL: {}.{}", sql_id, sub_sql_id)
}
}
for (key, value) in arg {
let id = format!("{}.#isNotEmpty#.{}", sql_id, key);
match SQL_CACHE.get(&id) {
Some(m) => {
sql = format!("{}\n{}", &sql, m);
}
_ => {}
}
let id = format!("{}.{}.#isNotEmpty#.{}", sql_id, sub_sql_id, key);
match SQL_CACHE.get(&id) {
Some(m) => {
sql = format!("{}\n{}", &sql, m);
}
_ => {}
}
if let Value::String(vl) = value {
let id = format!("{}.#isEqual#.{}.{}", sql_id, key, vl);
match SQL_CACHE.get(&id) {
Some(m) => {
sql = format!("{}\n{}", &sql, m);
}
_ => {}
}
let id = format!("{}.{}.#isEqual#.{}.{}", sql_id, sub_sql_id, key, vl);
match SQL_CACHE.get(&id) {
Some(m) => {
sql = format!("{}\n{}", &sql, m);
}
_ => {}
}
}
}
match SQL_CACHE.get(format!("{}.#footer#", sql_id).as_str()) {
Some(m) => {
sql = format!("{}\n{}", &sql, m);
}
_ =>{}
}
bind_variables(sql.as_str(), arg)
}
fn is_not_hidden(entry: &walkdir::DirEntry) -> bool {
entry
.file_name()
.to_str()
.map(|s| entry.depth() == 0 || !s.starts_with("."))
.unwrap_or(false)
}
pub fn get_table_column(){
println!("user_api_auth.update_datetime={:?}", DATA_TYPE_CACHE.get("user_api_auth.update_datetime"));
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}