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
mod table;
mod table_name;
mod data_type;
mod definition;
mod table_definition;
mod column;
mod index;
mod sequence;
mod foreign_key;


pub use column::{Column, ColumnOptions};
pub use data_type::DataType;
pub use definition::Definition;
pub use foreign_key::ForeignKey;
pub use index::{Index, IndexOptions};
pub use table::{Table, TableOptions, PrimaryKey, Timestamps};
pub use table_name::TableName;
pub use table_definition::TableDefinition;

#[derive(Copy, Clone, Debug)]
pub enum Dialect {
    Sqlite,
}

pub trait SqlUp {
    fn sqlite_up(&self) -> Option<String> {
        None
    }

    fn sqlite(&self) -> Option<String> {
        self.sql_up(Dialect::Sqlite)
    }

    fn sql_up(&self, dialect: Dialect) -> Option<String> {
        match dialect {
            Dialect::Sqlite => self.sqlite_up(),
        }
    }
}

pub trait SqlDown {
    fn sqlite_down(&self) -> Option<String> {
        None
    }

    fn sql_down(&self, dialect: Dialect) -> Option<String> {
        match dialect {
            Dialect::Sqlite => self.sqlite_down(),
        }
    }
}

#[cfg(test)]
macro_rules! create_tests {
    ($($name:ident: $value:expr,)*) => {
        $(
            #[test]
            fn $name() {
                let (input, expected) = $value;
                assert_eq!(input.sql_up(Dialect::Sqlite).unwrap().as_str(), expected.trim());
            }
        )*
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    create_tests!(
        test_table: (
            Definition::table("users", vec![
                TableDefinition::Column(Column::new("name")),
            ]), r#"
            CREATE TABLE users IF NOT EXISTS (id BIGINTEGER PRIMARY KEY AUTOINCREMENT, name STRING, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)
        "#),
        test_default_values_for_column: (Definition::column("users", DataType::String.column("name")), r#"
            ALTER TABLE users ADD COLUMN name STRING
        "#),
        test_default_not_null_column: (Definition::column("users", Column::new("name").not_null().to_owned()), r#"
            ALTER TABLE users ADD COLUMN name STRING NOT NULL
        "#),
        test_index: (Definition::index("users", Index::new(vec!["name".to_string()])), r#"
            CREATE INDEX name ON users (name)
        "#),
        test_foreign_key: (Definition::foreign_key("users", ForeignKey::new("other")), r#"
            ALTER TABLE users ADD FOREIGN KEY (other_id) REFERENCES other (id)
        "#),
    );
}