sql_db_creator 0.2.5

Generate sql databases by only configure the data of the databases in json files
Documentation
use crate::db::{ DBs, DB, Table };
use crate::util::reduce_str;
use crate::Config;

use std::collections::HashMap;
use futures::executor::block_on;
use serde_json::Value;
use sqlx::postgres::{ PgPool, PgQueryResult };
use sqlx::{Pool, Postgres, Error };

async fn create_connection(config: &Config) -> Result<Pool<Postgres>, Error> {
    let user = &config.user;
    let password = &config.password;
    let host = &config.host;

    let url = format!("postgres://{user}:{password}@{host}");

    PgPool::connect(&url).await
}

async fn create_db(name: &str, pool: &Pool<Postgres>) -> Result<PgQueryResult, Error> {
    let query = format!("CREATE DATABASE {name}");
    sqlx::query(&query).execute(pool).await
}

async fn drop_db(name: &str, pool: &Pool<Postgres>) -> Result<PgQueryResult, Error> {
    let query = format!("DROP DATABASE IF EXISTS {name}");
    sqlx::query(&query).execute(pool).await
}

async fn create_pool_for_db(config: &Config, db_name: &str) -> Result<Pool<Postgres>, Error> {
    let user = &config.user;
    let password = &config.password;
    let host = &config.host;

    let url = format!("postgres://{user}:{password}@{host}/{db_name}");

    PgPool::connect(&url).await
}

fn create_pools_for_dbs<'a>(config: &Config, dbs: &'a DBs, pool: &Pool<Postgres>) -> Vec::<(Pool<Postgres>, &'a DB)> {
    let mut pools: Vec::<(Pool<Postgres>, &DB)> = Vec::new();

    let dbs = &dbs.dbs;
    for db in dbs {
        match block_on(create_db(&db.name, &pool)) {
            Ok(_) => {
                println!("New Database with name \"{}\" created", &db.name);
                match block_on(create_pool_for_db(config, &db.name)) {
                    Ok(pool) => {
                        pools.push((pool, db));
                    },
                    Err(e) => {
                        println!("Error: {e}");
                        println!("Something went wron by trying to create the pool for the \"{}\" database", &db.name);
                    }
                }
            },
            Err(e) => {
                println!("Error: {e}");
                println!("Database with name \"{}\" couldn't be created", &db.name);
            }
        }
    }

    pools
}

async fn create_table(pool: &Pool<Postgres>, table: &Table) -> Result<PgQueryResult, Error> {
    let mut query = String::from("CREATE TABLE ");
    query.push_str(&table.name);
    query.push_str(" (");

    let schema = &table.schema;
    for (key, value) in schema {
        let value_new = &value[1..value.len() - 1];

        let line = format!("{} {}, ", key, value_new);
        query.push_str(&line);
    }

    let query_str = &query;
    let query_str_new = &query_str[0..query_str.len() - 2];
    
    let mut query = String::from(query_str_new);

    query.push_str(");");

    sqlx::query(&query).execute(pool).await
}

async fn create_table_data_set(pool: &Pool<Postgres>, table: &Table, data_set: &HashMap<String, Value>) -> Result<PgQueryResult, Error> {
    let mut column_names: Vec<&str> = Vec::new();
    let mut query = String::from("INSERT INTO ");
    query.push_str(&table.name);
    query.push_str(" (");

    let schema = &table.schema;
    for (s_key, _) in schema {
        for (d_key, _) in data_set {
            if s_key == d_key {
                let line = format!("{}, ", s_key);
                query.push_str(&line);
                column_names.push(&s_key);
            }
        }
    }
    
    let mut query = reduce_str(&query, 0, 2);

    query.push_str(") VALUES (");

    for name in &column_names {
        for (key, value) in data_set {
            if key == name {
                let mut value_new_string = String::from("");

                match value {
                    Value::Null => println!("Null"),
                    Value::Bool(b) => {
                        value_new_string.push_str(&b.to_string());
                    },
                    Value::Number(number) => {
                        value_new_string.push_str(&number.to_string());
                    },
                    Value::String(string) => {
                        value_new_string.push('\'');
                        value_new_string.push_str(string);
                        value_new_string.push('\'');
                    },
                    Value::Array(value) => println!("value: {:?}", value),
                    Value::Object(obj) => println!("obj: {:?}", obj)
                }

                if value_new_string != "" {
                    let line = format!("{}, ", value_new_string);
                    query.push_str(&line);
                }
            }
        }
    }

    let mut query = reduce_str(&query, 0, 2);
    query.push_str(");");

    sqlx::query(&query).execute(pool).await
}

pub fn setup_progres_sql(config: Config) {
    let dbs = DBs::new();
    let connection_pool_future_result = create_connection(&config);

    match block_on(connection_pool_future_result) {
        Ok(connection_pool) => {

            for db in &dbs.dbs {
                if let Err(_) = block_on(drop_db(&db.name, &connection_pool)) {
                    println!("Database \"{}\" could NOT be dropped. Probably the json has not the write format.", &db.name);
                } else {
                    println!("Database \"{}\" dropped if existed", &db.name);
                }
            }
            
            let pools = create_pools_for_dbs(&config, &dbs, &connection_pool);
            for (pool, db) in pools {

                let db_name = &db.name;
                let tables = &db.tables;

                for table in tables {
                    
                    let table_name = &table.name;
                    let table_result = create_table(&pool, &table);

                    if let Err(_) = block_on(table_result) {
                        println!("Table with name \"{}\" could NOT be created. Probably the json has not the write format.", table_name);
                    } else {
                        println!("New Table with name \"{}\" created in Database \"{}\".", table_name, db_name);

                        let min_size: usize = 0;
                        if &table.data.len() > &min_size {

                            let mut counter = 1;
                            for data in &table.data {
                                let data_set_result = create_table_data_set(&pool, &table, &data);

                                if let Err(_) = block_on(data_set_result) {
                                    println!("Table \"{}\" of Database \"{}\" could NOT be filled with a dataset. Probably the json has not the write format.", table_name, db_name);
                                } else {
                                    println!("Table \"{}\" of Database \"{}\" successfully filled with dataset Nr. {counter}", table_name, db_name);
                                    counter += 1;
                                }
                            }
                        }
                    }
                }
            }
        },
        Err(_) => println!("One or mor pools couldn't be created. Probably the login credantials are wrong.")
    }
}