bool BaseSqlDropTableService::execute(const Commands::ConstCommandPtr &command,
                                      CommandExecution::CommandExecutionContext &context) const
{
    QSharedPointer<const Commands::DropTable> dropTable(command.staticCast<const Commands::DropTable>());
    Q_ASSERT(dropTable);

    const Structure::Table originalTable( context.helperRepository().sqlStructureService().getTableDefinition(dropTable->tableName(), context.database()) );

    bool success = execute(*dropTable, context);

    if (success) {
        context.setUndoCommand(Commands::CommandPtr(new Commands::CreateTable(originalTable)));
    }
    return success;
}
bool SqliteDropColumnService::execute(const Commands::ConstCommandPtr &command,
                                      CommandExecution::CommandExecutionContext &context) const
{
    QSharedPointer<const Commands::DropColumn> dropColumn(command.staticCast<const Commands::DropColumn>());

    Structure::Table table( context.helperRepository().sqlStructureService().getTableDefinition(dropColumn->tableName(), context.database()) );
    Structure::Table::Builder alteredTable(dropColumn->tableName());
    const Structure::Column* originalColumn = Q_NULLPTR;
    foreach (const Structure::Column &column, table.columns()) {
        if (column.name() == dropColumn->columnName()) {
            originalColumn = &column;
        } else {
            alteredTable << column;
        }
    }
    if (!originalColumn) {
        ::qWarning() << "Column not found" << dropColumn->tableName() << dropColumn->columnName();
        return false;
    }

    QString tempTableName = QString("%1%2").arg(context.migrationConfig().temporaryTablePrefix, dropColumn->tableName());

    bool success = BaseSqlRenameTableService::execute(Commands::RenameTable(dropColumn->tableName(), tempTableName), context);
    if (!success)
        return false;

    success = BaseSqlCreateTableService::execute(Commands::CreateTable(alteredTable), context);
    if (!success)
        return false;

    const QString copyQuery =
            QString("INSERT INTO %1 SELECT %2 FROM %3")
            .arg(table.name())
            .arg(table.columnNames().join(", "))
            .arg(tempTableName);
    success = CommandExecution::BaseCommandExecutionService::executeQuery(copyQuery, context);
    if (!success)
        return false;

    success = BaseSqlDropTableService::execute(Commands::DropTable(tempTableName), context);

    if (success && context.isUndoUsed()) {
        context.setUndoCommand(Commands::CommandPtr(new Commands::AddColumn(*originalColumn, dropColumn->tableName())));
    }
    return success;
}
bool BaseMigrationTableService::removeMigration(const QString &migrationName,
                                                const CommandExecution::CommandExecutionContext &context) const
{
    const QString versionTableName = context.migrationConfig().migrationVersionTableName;
    const QString query =
            QString("DELETE FROM %1 WHERE version = %2")
            .arg(context.helperRepository().quoteService().quoteTableName(versionTableName))
            .arg(context.helperRepository().quoteService().quoteString(migrationName));
    ::qDebug() << "removing entry to version table. complete query looks like:";
    ::qDebug() << query;
    QSqlQuery sqlQuery = context.database().exec(query);
    if (sqlQuery.lastError().isValid()) {
        ::qDebug() << Q_FUNC_INFO << sqlQuery.lastError().text();
        return false;
    }
    return true;
}
QStringList BaseMigrationTableService::migrationList(const CommandExecution::CommandExecutionContext &context) const
{
    const QString versionTableName = context.migrationConfig().migrationVersionTableName;
    QSqlQuery sqlQuery = context.database().exec(
                QString("SELECT version FROM %1")
                .arg(context.helperRepository().quoteService().quoteTableName(versionTableName)));

    QStringList migrationList;
    if (sqlQuery.lastError().isValid()) {
        ::qDebug() << Q_FUNC_INFO << sqlQuery.lastError().text();
    } else {
        while (sqlQuery.next()) {
            migrationList << sqlQuery.value(0).toString();
        }
    }
    return migrationList;
}
bool MysqlRenameColumnService::execute(const Commands::ConstCommandPtr &command,
                                       CommandExecution::CommandExecutionContext &context) const
{
    QSharedPointer<const Commands::RenameColumn> renameColumn(command.staticCast<const Commands::RenameColumn>());
    Q_ASSERT(renameColumn);

    const Structure::Column originalColumn( context.helperRepository().sqlStructureService()
                                            .getTableDefinition(renameColumn->tableName(), context.database())
                                            .fetchColumnByName(renameColumn->oldName()) );
    if (!originalColumn.isValid()) {
        ::qWarning() << "could not find column" << renameColumn->tableName() << renameColumn->oldName();
        return false;
    }

    bool success = execute(*renameColumn, originalColumn, context);

    if (success && context.isUndoUsed()) {
        context.setUndoCommand(renameColumn->reverse());
    }
    return success;
}
bool CustomCommandService::down(const Commands::ConstCommandPtr &command, CommandExecution::CommandExecutionContext &context) const
{
    if(!command) {
        ::qDebug() << LOG_PREFIX << Q_FUNC_INFO << "command is 0!";
        return false;
    }

    QSharedPointer<const Commands::CustomCommandBase> customCommand(command.staticCast<const Commands::CustomCommandBase>());

    if(!customCommand) {
        ::qDebug() << LOG_PREFIX << Q_FUNC_INFO << "customCommand is 0!";
        return false;
    }

    return customCommand->down(context.database());
}
bool BaseSqlDropTableService::isValid(const Commands::ConstCommandPtr &command,
                                      const CommandExecution::CommandExecutionContext &context) const
{
    QSharedPointer<const Commands::DropTable> dropTable(command.staticCast<const Commands::DropTable>());

    //check if tableName is empty
    if (dropTable->tableName().isEmpty()) {
        ::qWarning() << "need to specify a table name!";
        return false;
    }

    //check if table exists
    if (!context.database().tables().contains(dropTable->tableName())) {
        ::qWarning() << "table doesn't exist!";
        return false;
    }

    return true;
}
bool PostgresqlAlterColumnTypeService::execute(const Commands::ConstCommandPtr &command
                                       , CommandExecution::CommandExecutionContext &context
                                       ) const
{
    QSharedPointer<const Commands::AlterColumnType> alterColumnType(command.staticCast<const Commands::AlterColumnType>());

    Structure::Column originalColumn;
    bool success = true;
    originalColumn = context.helperAggregate()
            .dbReaderService->getTableDefinition(alterColumnType->tableName(), context.database())
            .fetchColumnByName(alterColumnType->columnName(), success);

    if (!success)
        return success; // failed, column doesn't exist

    Structure::Column modifiedColumn(originalColumn.name(), alterColumnType->newType(), originalColumn.attributes());

    // alter {type, nullability, default, primary, unique} is handled by BaseSqlAlterColumnTypeService
    success = this->BaseSqlAlterColumnTypeService::execute(command, context);

    if (!success)
        return success; // execute failed

    QString alterQuery;
    // here we just need to handle auto increment (in PostgreSQL implemented as serial)
    if (modifiedColumn.isAutoIncremented() != originalColumn.isAutoIncremented()) {

        if (modifiedColumn.isAutoIncremented()) { // set auto increment
            alterQuery = QString("CREATE SEQUENCE %1_%2_seq;").arg(alterColumnType->tableName(),
                                                                           alterColumnType->columnName());
            success = CommandExecution::BaseCommandExecutionService::executeQuery(alterQuery, context);

            if (!success)
                return success; // query failed

            // serials also get NOT NULL attribute set, so we need to set that, too
            alterQuery = QString("ALTER TABLE %1 ALTER COLUMN %2 SET NOT NULL")
                    .arg(context.helperAggregate().quoteService->quoteTableName(alterColumnType->tableName())
                         , context.helperAggregate().quoteService->quoteColumnName(originalColumn.name()));

            success = CommandExecution::BaseCommandExecutionService::executeQuery(alterQuery, context);

            if (!success)
                return success; // query failed

            // auto increment is implemented as default value (call to function), so we need to set it
            alterQuery = QString("ALTER TABLE %1 ALTER COLUMN %2 SET DEFAULT nextval('%1_%2_seq')")
                    .arg(context.helperAggregate().quoteService->quoteTableName(alterColumnType->tableName())
                         , context.helperAggregate().quoteService->quoteColumnName(originalColumn.name()));

            success = CommandExecution::BaseCommandExecutionService::executeQuery(alterQuery, context);

            if (!success)
                return success; // query failed

            // mark sequence to be "owned by" the column, so that it will be dropped if the column or table is dropped
            alterQuery = QString("ALTER SEQUENCE %1_%2_seq OWNED BY %1.%2").arg(
                        alterColumnType->tableName()
                        , alterColumnType->columnName());

            success = CommandExecution::BaseCommandExecutionService::executeQuery(alterQuery, context);

            if (!success)
                return success; // query failed

        } else { // drop auto increment
            // auto increment is implemented as default value (call to function), so we need to drop it
            alterQuery = QString("ALTER TABLE %1 ALTER COLUMN %2 DROP DEFAULT")
                    .arg(context.helperAggregate().quoteService->quoteTableName(alterColumnType->tableName())
                         , context.helperAggregate().quoteService->quoteColumnName(originalColumn.name()));

            success = CommandExecution::BaseCommandExecutionService::executeQuery(alterQuery, context);

            if (!success)
                return success; // query failed

            // serials also get NOT NULL attribute set, so we need to remove that, too
            alterQuery = QString("ALTER TABLE %1 ALTER COLUMN %2 DROP NOT NULL")
                    .arg(context.helperAggregate().quoteService->quoteTableName(alterColumnType->tableName())
                         , context.helperAggregate().quoteService->quoteColumnName(originalColumn.name()));

            success = CommandExecution::BaseCommandExecutionService::executeQuery(alterQuery, context);

            if (!success)
                return success; // query failed
        }
    }

    return success;
}