Improved support from removing rows in crud tabs.

It can handle now complex selections and reports back errors encountered
when removing the rows fails.
This commit is contained in:
eelke 2018-12-15 11:24:58 +01:00
parent 950fea873c
commit 62c6ad5bfb
10 changed files with 365 additions and 116 deletions

View file

@ -13,7 +13,9 @@
#include <QFuture>
#include <QFutureWatcher>
#include "Pgsql_oids.h"
#include "Pgsql_PgException.h"
#include "Pgsql_Params.h"
#include "Pgsql_Transaction.h"
#include <string>
#include "ScopeGuard.h"
@ -94,7 +96,6 @@ CrudModel::Value CrudModel::getData(const QModelIndex &index) const
int col = index.column();
auto row_mapping = m_rowMapping[grid_row];
const int last_row = rowCount() - 1;
//Oid o = m_roData->type(col);
@ -225,7 +226,7 @@ void CrudModel::connectionStateChanged(ASyncDBConnection::State state)
Qt::ItemFlags CrudModel::flags(const QModelIndex &) const
{
Qt::ItemFlags flags = Qt::ItemIsSelectable + Qt::ItemIsEnabled;
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (m_primaryKey) {
flags |= Qt::ItemIsEditable;
}
@ -508,16 +509,12 @@ void CrudModel::appendNewRow()
endInsertRows();
}
void CrudModel::removeRows()
{
// determine selection
// remove selected rows
}
bool CrudModel::removeRows(int row, int count, const QModelIndex &parent)
std::tuple<bool, QString> CrudModel::removeRows(const std::set<IntegerRange<int>> &row_ranges)
{
if (m_rowMapping.empty()) return false;
if (row_ranges.empty()) return { true, "" };
if (row_ranges.rbegin()->end() > m_rowMapping.size()) return { false, "Range error" };
// When removing rows there is no direct mapping anymore between the rows in the grid
// and the rows in m_roData
@ -527,42 +524,69 @@ bool CrudModel::removeRows(int row, int count, const QModelIndex &parent)
// 1. Get PKEY and remove that row from table
Pgsql::Connection db_update_conn;
auto dbconfig = m_database->config();
bool res = db_update_conn.connect(dbconfig.getKeywords(), dbconfig.getValues(), false);
if (!res) {
return false;
}
// First delete rows in table
QString delete_statement = createDeleteStatement();
db_update_conn.query("BEGIN;");
for (int current_row = row; current_row < row + count; ++current_row) {
auto&& mapping = m_rowMapping[static_cast<size_t>(current_row)];
auto params = getPKeyParamsForRow(mapping.rowKey);
if (!params.empty()) {
// Execute DELETE
auto result = db_update_conn.queryParam(delete_statement, params);
try {
Pgsql::Connection db_update_conn;
auto dbconfig = m_database->config();
bool res = db_update_conn.connect(dbconfig.getKeywords(), dbconfig.getValues(), false);
if (!res) {
return { false, "Cannot connect to the database" };
}
}
db_update_conn.query("COMMIT;");
// Then from model
{
beginRemoveRows(parent, row, row);
SCOPE_EXIT { endRemoveRows(); };
for (int current_row = row; current_row < row + count; ++current_row) {
auto&& mapping = m_rowMapping[static_cast<size_t>(current_row)];
// if the row is in modified it can be removed from modified
if (mapping.modified) {
m_modifiedRowList.erase(mapping.rowKey);
// First delete rows in table
QString delete_statement = createDeleteStatement();
{
db_update_conn.query("BEGIN;");
auto tx = Pgsql::Transaction::startTransaction(db_update_conn);
for (auto range : row_ranges) {
for (int current_row = range.start(); current_row < range.end(); ++current_row) {
auto&& mapping = m_rowMapping[static_cast<size_t>(current_row)];
auto params = getPKeyParamsForRow(mapping.rowKey);
if (!params.empty()) {
// Execute DELETE
db_update_conn.queryParam(delete_statement, params);
}
}
}
/// \todo can it be pending? should be removed if it is.
tx.commit();
// If something goes wrong after this commit we should reload contents of model
}
// remove the rows from m_rowMapping
auto first = m_rowMapping.begin() + row;
m_rowMapping.erase(first, first + count);
// Then from model
{
int rows_deleted = 0;
for (auto range : row_ranges) {
range.setStart(range.start() - rows_deleted);
beginRemoveRows(QModelIndex(), range.start(), range.end() - 1);
SCOPE_EXIT { endRemoveRows(); };
for (int current_row = range.start(); current_row < range.end(); ++current_row) {
auto&& mapping = m_rowMapping[static_cast<size_t>(current_row)];
// if the row is in modified it can be removed from modified
if (mapping.modified) {
m_modifiedRowList.erase(mapping.rowKey);
}
/// \todo can it be pending? should be removed if it is.
}
// remove the rows from m_rowMapping
auto first = m_rowMapping.begin() + range.start();
m_rowMapping.erase(first, first + range.length());
rows_deleted += range.length();
}
}
return { true, "" };
} catch (const Pgsql::PgResultError &error) {
return { false, QString::fromUtf8(error.details().messageDetail.c_str()) };
}
return true;
}
bool CrudModel::removeRows(int row, int count, const QModelIndex &)
{
if (m_rowMapping.empty()) return false;
IntegerRange<int> range(row, count);
auto [res, message] = removeRows({ range });
return res;
}