models 0.1.3

A migration management library for applications using PostgresSQL, MySQL or SQLite.
use super::*;
mod temp_move;
use temp_move::Move;
#[derive(Debug)]
pub(crate) struct Action<'table> {
    pub table_name: &'table ObjectName,
    pub variant: ActionVariant<'table>,
}
#[derive(Debug)]
pub(crate) enum ActionVariant<'table> {
    CreateCol(&'table Column),

    DropCol(Ident),

    CreateConstr(&'table TableConstraint),

    DropConstr(Ident),

    TempMove(Move<'table>),

    CreateTable(&'table Table),
}

impl<'table> Action<'table> {
    pub fn is_fallible(&self) -> bool {
        if let ActionVariant::CreateCol(col) = &self.variant {
            col.has_default() || col.is_nullable()
        } else {
            false
        }
    }

    pub(super) fn create_table(target: &'table Table) -> Self {
        Self {
            table_name: &target.name,
            variant: ActionVariant::CreateTable(target),
        }
    }
    pub(super) fn drop_cons(
        name: &'table ObjectName,
        cons: &'table TableConstraint,
    ) -> Result<Self> {
        Ok(Self {
            table_name: name,
            variant: ActionVariant::DropConstr(Ident::new(cons.name()?)),
        })
    }

    pub(super) fn drop_col(name: &'table ObjectName, col: &'table Column) -> Self {
        Self {
            table_name: name,
            variant: ActionVariant::DropCol(col.name.clone()),
        }
    }
    pub(super) fn create_column(table_name: &'table ObjectName, col: &'table Column) -> Self {
        Self {
            table_name,
            variant: ActionVariant::CreateCol(col),
        }
    }
    pub(super) fn create_cons(name: &'table ObjectName, cons: &'table TableConstraint) -> Self {
        Self {
            table_name: name,
            variant: ActionVariant::CreateConstr(cons),
        }
    }
    pub fn move_to(old: &'table Table, cols: &ColCRUD<'table>, cons: &ConsCRUD<'table>) -> Self {
        let move_ = Move::new(old, cons, cols);
        Self {
            table_name: &old.name,
            variant: ActionVariant::TempMove(move_),
        }
    }

    pub fn to_statements(self) -> Result<Vec<Statement>> {
        use ActionVariant::*;
        let mut out = vec![];
        let table_name = self.table_name.clone();
        match self.variant {
            TempMove(r#move) => {
                return r#move.to_statements(table_name);
            }
            CreateTable(table) => {
                let statement = Statement::from(table.clone());
                out.push(statement);
            }
            other => {
                let operation = match other {
                    CreateCol(column) => AlterTableOperation::AddColumn {
                        column_def: ColumnDef::from(column.clone()),
                    },

                    DropCol(column_name) => AlterTableOperation::DropColumn {
                        column_name,
                        if_exists: false,
                        cascade: DIALECT.supports_cascade(),
                    },
                    DropConstr(name) => AlterTableOperation::DropConstraint {
                        name,
                        cascade: DIALECT.supports_cascade(),
                        restrict: false,
                    },
                    CreateConstr(constr) => AlterTableOperation::DropConstraint {
                        name: Ident::new(constr.name().unwrap()),
                        cascade: DIALECT.supports_cascade(),
                        restrict: false,
                    },

                    _ => todo!(),
                };

                let statement = Statement::AlterTable(AlterTable {
                    name: table_name,
                    operation,
                });
                out.push(statement);
            }
        }
        Ok(out)
    }
}

pub fn depends(cons: &TableConstraint, tables: &[&Column]) -> bool {
    let names = match cons {
        TableConstraint::ForeignKey(fk) => &fk.columns,
        TableConstraint::Unique(unique) => &unique.columns,
        _ => return false,
    };
    let names = names.iter().map(ToString::to_string);

    for col in names {
        for table_name in tables.iter().map(|t| t.name().unwrap()) {
            if col.to_string() == table_name {
                return true;
            }
        }
    }
    false
}