Improve CrudModel code quality

This commit is contained in:
eelke 2026-10-18 17:55:26 +02:00
parent 82cc9f14bc
commit 550049ceff
6 changed files with 870 additions and 205 deletions

View file

@ -60,11 +60,10 @@ signals:
/// Emitted when the model goes from clean to having pending changes or back
void pendingChangesChanged(bool hasChanges);
public slots:
private:
const int PreColumnCount = 1;
/// Number of grid columns in front of the result columns (the row number column)
static constexpr int PreColumnCount = 1;
class ColumnSort {
@ -125,17 +124,6 @@ private:
public:
using Map = std::map<int, PendingRow>;
PendingRow& getRow(int row)
{
auto iter = m_rows.lower_bound(row);
if (iter != m_rows.end() && iter->first == row) {
return iter->second;
}
else {
return m_rows.insert(iter, {row, PendingRow(row)})->second;
}
}
void setValue(int col, int row, const Value &value)
{
auto iter = m_rows.find(row);
@ -226,13 +214,7 @@ private:
std::shared_ptr<Pgsql::Result> m_roData;
struct ColumnData
{
std::string name;
// identity allways or generated
};
std::vector<std::optional<PgAttribute>> columnList; // attribute per column in m_roData, empty for expression columns
std::vector<std::optional<PgAttribute>> m_columnList; // attribute per column in m_roData, empty for expression columns
PendingRowList m_pendingRowList;
@ -242,47 +224,64 @@ private:
/// call on initial load to fill in the mappings
void initRowMapping();
/// Value as shown in the grid, pending edits take precedence over saved data
Value getLatestData(int column, int row) const;
Value getLatestData(const QModelIndex &index) const
{
return getLatestData(index.column() - PreColumnCount, index.row());
}
Value getSavedData(int columnIndex, int rowIndex) const;
/// Value as last loaded from or saved to the database
Value getSavedData(const RowMapping &row_mapping, int columnIndex) const;
/// Mapping of the row with the given key, nullptr when the row is not in the grid (anymore)
RowMapping* findRowMapping(int rowKey);
/// Call after changing the pending rows to emit pendingChangesChanged when the state toggled
void updatePendingState(bool was_dirty);
Oid getType(int column) const;
/// Get the PKey values from when the row was last restored or retrieved.
Pgsql::Params getPKeyParamsForRow(const RowMapping &row_mapping, Oid table_oid) const;
// ---- Saving, all of these only use the data of the pending row and the row mapping
bool savePendingChanges();
/// Inserts the row when it is new otherwise updates it. Returns the values of the row as stored in the database.
std::tuple<bool, std::vector<Value>> saveRow(const PendingRow &pending_row, const RowMapping &row_mapping);
std::tuple<bool, std::vector<Value>> saveUpdate(const PendingRow &pending_row, const RowMapping &row_mapping);
std::tuple<QString, Pgsql::Params> createUpdateQuery(Oid table_oid, const PendingRow &pending_row, const RowMapping &row_mapping);
/// Get the PKey values from when the row was last restored or retrieved.
Pgsql::Params getPKeyParamsForRow(const RowMapping &row_mapping, Oid table_oid) const;
std::tuple<QString, Pgsql::Params> createUpdateQuery(Oid table_oid, const PendingRow &pending_row, const RowMapping &row_mapping);
std::tuple<QString, Pgsql::Params> createInsertQuery(const PendingRow &pending_row);
QString createDeleteStatement() const;
std::tuple<bool, std::vector<Value>> saveRow(const PendingRow &pending_row, const RowMapping &row_mapping);
std::tuple<bool, std::vector<Value>> saveUpdate(const PendingRow &pending_row, const RowMapping &row_mapping);
/// Opens a separate connection for writing so edits don't interfere with the loading connection
void connectForUpdate(Pgsql::Connection &connection) const;
/// Tells the user about a failed write, the one place where the model shows a dialog
void reportError(const QString &message) const;
static std::vector<Value> rowValues(const Pgsql::Row &row);
// ---- Rows
void appendNewRow();
void appendNewRowInternal();
void appendNewRowInternal();
int lastRowKey = -1;
int lastRowKey = -1;
int allocNewRowKey() { return ++lastRowKey; }
/// Deletes the rows from the database in one transaction, throws on failure
void deleteRowsFromDatabase(const std::set<IntegerRange<int>> &row_ranges);
/// Removes the rows from the grid and drops their pending edits
void removeRangesFromModel(const std::set<IntegerRange<int>> &row_ranges);
void removeRangeFromModel(IntegerRange<int> row_range);
// ---- Table and column information
/// Name of the table with the given oid, quoted and schema qualified
QString tableName(Oid table_oid) const;
/// Result columns that are user columns (attnum > 0) of the given table, in result order
std::vector<int> resultColumnsOfTable(Oid table_oid) const;
/// Catalog name of the attribute behind a result column, falls back to the result column name
QString attributeName(int col) const;
bool columnIsReadOnly(int column_index) const;
void initializeColumnList();
void RemoveRangesOfRowsFromModel(const std::set<IntegerRange<int>> &row_ranges);
void RemoveRangeOfRowsFromModel(IntegerRange<int> row_range);
bool IsLastRow(RowMappingVector::iterator mapping_iter) const;
bool columnIsReadOnly(int column_index) const;
void initializeColumnList();
private slots:
void loadIntoModel(std::shared_ptr<Pgsql::Result> data);