1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
pub mod commands;
pub mod config;
pub mod errors;
pub mod generators;
use crate::errors::{Result, WeldsError};
use config::DbProvider;
use std::path::PathBuf;
use welds::connection::AnyPool;
use welds::table::TableIdent;

pub async fn update(schema_path: PathBuf, identifier: Option<String>) -> Result<()> {
    use welds::detect::find_tables;
    let identifier = identifier.as_ref().map(|x| TableIdent::parse(x));
    let unknown_pool = AnyPool::connect().await?;

    let provider = match unknown_pool {
        AnyPool::Postgres(_) => DbProvider::Postgres,
        AnyPool::MySql(_) => DbProvider::Mysql,
        AnyPool::Mssql(_) => DbProvider::Mssql,
        AnyPool::Sqlite(_) => DbProvider::Sqlite,
    };

    let mut tables = match unknown_pool {
        AnyPool::Postgres(conn) => find_tables(&conn).await?,
        AnyPool::Mssql(conn) => find_tables(&conn).await?,
        AnyPool::MySql(conn) => find_tables(&conn).await?,
        AnyPool::Sqlite(conn) => find_tables(&conn).await?,
    };

    let mut conf_def = config::read(&schema_path).unwrap_or_default();

    match identifier {
        Some(identifier) => {
            // update only the specified table
            tables.retain(|t| t.ident() == &identifier);
            if tables.is_empty() {
                log::error!(
                    "Table not found: no table updated  (HINT: make sure you include the schema)"
                );
            }
            conf_def.add_update(&tables, provider);
        }
        None => {
            conf_def.remove_missing(&tables);
            conf_def.add_update(&tables, provider);
        }
    };

    config::write(&schema_path, &conf_def)?;
    Ok(())
}

#[derive(Debug, Default)]
pub struct GenerateOption {
    pub schema_path: PathBuf,
    pub output_path: PathBuf,
    pub table: Option<String>,
}

pub fn generate(mut opt: GenerateOption) -> Result<()> {
    if !opt.schema_path.exists() {
        return Err(WeldsError::MissingSchemaFile(opt.schema_path));
    }

    let conf_def = config::read(&opt.schema_path)?;

    clean_code_output_path(&mut opt);
    generators::models::run(&conf_def, &opt)?;

    Ok(())
}

/// If the path is the root of a project, add on ./src/models
/// If the use is giving a path directly allow it to fly
fn clean_code_output_path(opt: &mut GenerateOption) {
    if is_project_path(&opt.output_path) {
        let mut new_path = PathBuf::from(&opt.output_path);
        new_path.push("src");
        new_path.push("models");
        opt.output_path = new_path;
    }
}

fn is_project_path(path: &PathBuf) -> bool {
    if !path.exists() || !path.is_dir() {
        return false;
    }
    let mut src = PathBuf::from(path);
    src.push("src");
    if !src.exists() || !src.is_dir() {
        return false;
    }
    let mut cargo_toml = PathBuf::from(path);
    cargo_toml.push("Cargo.toml");
    if !cargo_toml.exists() || !cargo_toml.is_file() {
        return false;
    }
    true
}

/// tests the underlying database connection set with DATABASE_URL
pub async fn test_connection() -> Result<()> {
    let result = AnyPool::connect().await;
    match result {
        Ok(_) => {
            println!("Database connected successfully");
            std::process::exit(0);
        }
        Err(_) => {
            eprintln!("Not able to connect to database");
            std::process::exit(1);
        }
    }
}