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
use crate::errors::{Result, WeldsError};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use welds::Syntax;

mod table;
pub use table::Table;

mod column;
pub use column::Column;

///
/// This module holds the Struct and functions for welds.yaml configs
///

/// Reads in a schema config file and parses it into a config
pub(crate) fn read(path: &PathBuf) -> Result<Config> {
    let yaml_str =
        std::fs::read_to_string(path).map_err(|_| WeldsError::ReadError(path.clone()))?;
    let config: std::result::Result<Config, serde_yaml::Error> = serde_yaml::from_str(&yaml_str);
    match config {
        Err(_err) => Err(WeldsError::ConfigReadError(path.clone())),
        Ok(config) => Ok(config),
    }
}

/// Writes a schema config file to disk
pub(crate) fn write(path: &PathBuf, config: &Config) -> Result<()> {
    let yaml = serde_yaml::to_string(config).map_err(|_| WeldsError::ConfigWrite)?;
    std::fs::write(path, yaml.as_bytes())?;
    Ok(())
}

#[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct Config {
    pub tables: Vec<Table>,
}

impl Config {
    pub(crate) fn remove_missing(&mut self, tables: &[welds::detect::TableDef]) {
        let idents: Vec<_> = tables.iter().map(|x| x.ident()).collect();
        // Remove Deleted tables
        self.tables
            .retain(|x| x.manual_update || idents.contains(&&x.ident()));
    }

    pub(crate) fn add_update(&mut self, provider: DbProvider, tables: &[welds::detect::TableDef]) {
        // Build a list of new columns to add.
        let mut to_add = Vec::default();
        // Add or update
        for t in tables {
            let existing = self.tables.iter_mut().find(|x| &x.ident() == t.ident());
            match existing {
                Some(existing) => existing.update_from(t, provider),
                None => to_add.push(Table::new(t, provider)),
            }
        }
        // append new tables
        self.tables.append(&mut to_add);
    }
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct Relation {
    pub schema: Option<String>, // What schema this table belongs to
    pub tablename: String,      // Table name
    pub foreign_key: String,    // The foreign_key column
}

impl From<&welds::detect::RelationDef> for Relation {
    fn from(value: &welds::detect::RelationDef) -> Self {
        Relation {
            schema: value.other_table().schema().map(|x| x.to_owned()),
            tablename: value.other_table().name().to_owned(),
            foreign_key: value.foreign_key().to_owned(),
        }
    }
}

#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone, Copy)]
pub enum DbProvider {
    Postgres,
    Mysql,
    Mssql,
    Sqlite,
}

impl From<Syntax> for DbProvider {
    fn from(syntax: Syntax) -> Self {
        match syntax {
            Syntax::Mysql => DbProvider::Mysql,
            Syntax::Postgres => DbProvider::Postgres,
            Syntax::Mssql => DbProvider::Mssql,
            Syntax::Sqlite => DbProvider::Sqlite,
        }
    }
}

impl From<DbProvider> for Syntax {
    fn from(provider: DbProvider) -> Syntax {
        match provider {
            DbProvider::Mysql => Syntax::Mysql,
            DbProvider::Postgres => Syntax::Postgres,
            DbProvider::Mssql => Syntax::Mssql,
            DbProvider::Sqlite => Syntax::Sqlite,
        }
    }
}