The table inheritance works mostly

This commit is contained in:
Eelke Klein 2023-01-24 17:47:52 +00:00
parent ccd88d0578
commit 2ff9577d41
22 changed files with 473 additions and 145 deletions

View file

@ -38,9 +38,9 @@ public:
virtual Oid getType(int column) const override;
virtual QVariant getData(const QModelIndex &index) const override;
RowItem rowItem(int row) const
RowItem rowItem(const QModelIndex &index) const
{
return databases.at(row).database;
return databases.at(index.row()).database;
}
protected:
virtual QVariant getDataMeaning(const QModelIndex &index) const override;

View file

@ -5,15 +5,16 @@
#include "catalog/PgClass.h"
#include "catalog/PgClassContainer.h"
#include "catalog/PgNamespace.h"
#include "catalog/PgNamespaceContainer.h"
#include "Pgsql_declare.h"
#include "catalog/PgInheritsContainer.h"
//#include "Pgsql_declare.h"
#include "ui/catalog/tables/TableTreeBuilder.h"
#include "CustomDataRole.h"
#include <QBrush>
#include <QtConcurrent>
#include "Pgsql_Connection.h"
TablesTableModel::TablesTableModel(std::shared_ptr<OpenDatabase> opendatabase, QObject *parent)
: QAbstractTableModel(parent)
: QAbstractItemModel(parent)
, openDatabase(opendatabase)
{}
@ -36,17 +37,18 @@ void TablesTableModel::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
bool TableLike(RelKind relkind)
{
switch (relkind) {
case RelKind::Table:
case RelKind::View:
case RelKind::MaterializedView:
case RelKind::ForeignTable:
case RelKind::PartitionedTable:
return true;
default:
return false;
case RelKind::Table:
case RelKind::View:
case RelKind::MaterializedView:
case RelKind::ForeignTable:
case RelKind::PartitionedTable:
return true;
default:
return false;
}
}
void TablesTableModel::refresh()
{
beginResetModel();
@ -55,31 +57,19 @@ void TablesTableModel::refresh()
if (!m_catalog)
return;
// Later afscheiden naar filter functie
auto classes = m_catalog->classes();
rootNode.reset();
auto nsfilter = GetNamespaceFilterLambda();
std::map<Oid, PgClass> temp;
for (const auto &e : *classes)
if (TableLike(e.kind) && nsfilter(e))
temp.emplace(e.oid(), e);
TableTreeBuilder treeBuilder(temp, *m_catalog->inherits());
auto [rn, oidIndex] = treeBuilder.Build();
rootNode = rn;
std::map<Oid, int> oidIndex;
m_tables.clear();
for (const auto &e : *classes) {
bool add = false;
if (TableLike(e.kind)) {
switch (m_namespaceFilter) {
case NamespaceFilter::User:
add = !e.ns().isSystemCatalog();
break;
case NamespaceFilter::PgCatalog:
add = e.ns().objectName() == "pg_catalog";
break;
case NamespaceFilter::InformationSchema:
add = e.ns().objectName() == "information_schema";
break;
}
}
if (add) {
m_tables.emplace_back(e);
oidIndex.emplace(e.oid(), m_tables.size() - 1);
}
}
StartLoadTableSizes(std::move(oidIndex));
}
@ -106,14 +96,46 @@ QVariant TablesTableModel::headerData(int section, Qt::Orientation orientation,
return QVariant();
}
int TablesTableModel::rowCount(const QModelIndex &) const
int TablesTableModel::rowCount(const QModelIndex &parent) const
{
return static_cast<int>(m_tables.size());
if (parent.isValid())
{
const TableNode *parentItem = static_cast<const TableNode*>(parent.internalPointer());
return static_cast<int>(parentItem->children.size());
}
if (rootNode != nullptr)
return static_cast<int>(rootNode->children.size());
return 0;
}
int TablesTableModel::columnCount(const QModelIndex &) const
{
return colCount;
return colCount;
}
QModelIndex TablesTableModel::index(int row, int column, const QModelIndex &parent) const
{
if (parent.isValid())
{
const TableNode *parentItem = static_cast<const TableNode*>(parent.internalPointer());
return createIndex(row, column, parentItem->getChildPtr(row));
}
return createIndex(row, column, rootNode->getChildPtr(row));
}
QModelIndex TablesTableModel::parent(const QModelIndex &index) const
{
if (index.isValid())
{
const TableNode *item = static_cast<const TableNode*>(index.internalPointer());
auto parent = item->parent.lock();
if (parent && parent != rootNode)
{
return createIndex(parent->myIndex, 0, parent.get());
}
}
return {};
}
Oid TablesTableModel::getType(int column) const
@ -142,37 +164,29 @@ Oid TablesTableModel::getType(int column) const
QVariant TablesTableModel::getData(const QModelIndex &index) const
{
const auto &table = m_tables[index.row()];
const auto &t = table._class;
const auto &s = table.sizes;
// const auto &table = rootNode->children[index.row()];
const TableNode* table = nodeFromIndex(index);
const auto &t = table->_class;
const auto &s = table->sizes;
switch (index.column()) {
case NameCol: return t.objectName();
case NamespaceCol: return t.nsName();
case KindCol: return t.typeName();
case OwnerCol: return t.ownerName();
case TablespaceCol: return getTablespaceDisplayString(*m_catalog, t.tablespace);
case OptionsCol: break;
case AclCol: return t.aclString();
case CommentCol: return t.description;
case TotalSizeCol: return s.oid == 0 ? QVariant() : s.totalBytes;
case TableSizeCol: return s.oid == 0 ? QVariant() : s.totalBytes - s.indexBytes - s.toastBytes;
case IndexSizeCol: return s.oid == 0 ? QVariant() : s.indexBytes;
case ToastSizeCol: return s.oid == 0 ? QVariant() : s.toastBytes;
case NameCol: return t.objectName();
case NamespaceCol: return t.nsName();
case KindCol: return t.typeName();
case OwnerCol: return t.ownerName();
case TablespaceCol: return getTablespaceDisplayString(*m_catalog, t.tablespace);
case OptionsCol: break;
case AclCol: return t.aclString();
case CommentCol: return t.description;
case TotalSizeCol: return s.oid == 0 ? QVariant() : s.totalBytes;
case TableSizeCol: return s.oid == 0 ? QVariant() : s.totalBytes - s.indexBytes - s.toastBytes;
case IndexSizeCol: return s.oid == 0 ? QVariant() : s.indexBytes;
case ToastSizeCol: return s.oid == 0 ? QVariant() : s.toastBytes;
}
return QVariant();
}
PgClass TablesTableModel::getTable(int row) const
{
return m_tables[row]._class;
}
Oid TablesTableModel::getTableOid(int row) const
{
return m_tables[row]._class.oid();
}
QVariant TablesTableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
@ -195,7 +209,7 @@ QVariant TablesTableModel::data(const QModelIndex &index, int role) const
return QVariant();
}
void TablesTableModel::StartLoadTableSizes(std::map<Oid, int> oidIndex)
void TablesTableModel::StartLoadTableSizes(OidClassIndex oidIndex)
{
QPointer p(this);
QtConcurrent::run([this]
@ -205,7 +219,7 @@ void TablesTableModel::StartLoadTableSizes(std::map<Oid, int> oidIndex)
.then(qApp, [p, oidIndex] (TableSizes sizes)
{
if (p)
p.data()->PopulateSizes(std::move(oidIndex), std::move(sizes));
p.data()->PopulateSizes(oidIndex, sizes);
});
}
@ -254,18 +268,41 @@ TablesTableModel::TableSizes TablesTableModel::QueryTableSizes() const
return sizes;
}
void TablesTableModel::PopulateSizes(std::map<Oid, int> oidIndex, std::vector<TableSize> sizes)
void TablesTableModel::PopulateSizes(
const OidClassIndex &oidIndex,
const std::vector<TableSize> &sizes
)
{
for (auto s : sizes)
{
auto findIter = oidIndex.find(s.oid);
if (findIter != oidIndex.end())
{
m_tables[findIter->second].sizes = s;
findIter->second->sizes = s;
}
}
emit dataChanged(
createIndex(0, TotalSizeCol),
createIndex(static_cast<int>(m_tables.size()), ToastSizeCol)
);
index(0, TotalSizeCol),
index(static_cast<int>(rootNode->children.size()), ToastSizeCol)
);
}
const TableNode* TablesTableModel::nodeFromIndex(const QModelIndex &index)
{
return static_cast<const TableNode*>(index.internalPointer());
}
std::function<bool (const PgClass &)> TablesTableModel::GetNamespaceFilterLambda()
{
switch (m_namespaceFilter) {
case NamespaceFilter::User:
return [] (const PgClass &c) { return !c.ns().isSystemCatalog(); };
case NamespaceFilter::PgCatalog:
return [] (const PgClass &c) { return c.ns().objectName() == "pg_catalog"; };
case NamespaceFilter::InformationSchema:
return [] (const PgClass &c) { return c.ns().objectName() == "information_schema"; };
}
}

View file

@ -1,9 +1,12 @@
#ifndef TABLESTABLEMODEL_H
#ifndef TABLESTABLEMODEL_H
#define TABLESTABLEMODEL_H
#include "BaseTableModel.h"
//#include "catalog/models/BaseTableModel.h"
#include "ui/catalog/tables/TableNode.h"
#include "ui/catalog/tables/TableSize.h"
#include "NamespaceFilter.h"
#include "catalog/PgClass.h"
#include <QAbstractItemModel>
#include <memory>
#include <vector>
@ -11,7 +14,7 @@ class OpenDatabase;
class PgClass;
class PgDatabaseCatalog;
class TablesTableModel: public QAbstractTableModel {
class TablesTableModel: public QAbstractItemModel {
public:
using RowItem = PgClass;
enum e_Columns : int {
@ -40,42 +43,31 @@ public:
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
virtual QVariant data(const QModelIndex &index, int role) const override;
PgClass getTable(int row) const;
RowItem rowItem(int row) const
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
QVariant data(const QModelIndex &index, int role) const override;
RowItem rowItem(const QModelIndex &index) const
{
return getTable(row);
return nodeFromIndex(index)->_class;
}
Oid getTableOid(int row) const;
static const TableNode* nodeFromIndex(const QModelIndex &index);
private:
class TableSize {
public:
int oid;
int64_t totalBytes = -1;
int64_t indexBytes = -1;
int64_t toastBytes = -1;
TableSize()
: oid(0)
{}
};
using TableSizes = std::vector<TableSize>;
class Table {
public:
PgClass _class;
TableSize sizes;
Table(const PgClass &cls)
: _class(cls)
{}
};
using t_Tables = std::vector<Table>;
// this is a readonly model so when the vectors have been filled
// they will not change anymore and it is safe to assume the indexes
// of elements do not change
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
NamespaceFilter m_namespaceFilter = NamespaceFilter::User;
t_Tables m_tables;
std::shared_ptr<TableNode> rootNode;
QMetaObject::Connection refreshConnection;
std::shared_ptr<OpenDatabase> openDatabase;
@ -83,10 +75,17 @@ private:
Oid getType(int column) const;
QVariant getData(const QModelIndex &index) const;
void StartLoadTableSizes(std::map<Oid, int> oidIndex);
TableSizes QueryTableSizes() const;
void PopulateSizes(std::map<Oid, int> oidIndex, std::vector<TableSize> sizes);
using OidClassIndex = std::map<Oid, std::shared_ptr<TableNode>>;
void StartLoadTableSizes(OidClassIndex oidIndex);
TableSizes QueryTableSizes() const;
void PopulateSizes(
const OidClassIndex &oidIndex,
const std::vector<TableSize> &sizes
);
std::function<bool(const PgClass&)> GetNamespaceFilterLambda();
private slots:
void refresh();

View file

@ -8,7 +8,7 @@
#include "catalog/widgets/TriggerPage.h"
#include "catalog/models/ColumnTableModel.h"
#include "catalog/models/ConstraintModel.h"
#include "catalog/models/TablesTableModel.h"
#include "catalog/tables/TablesTableModel.h"
#include "util/PgLabTableView.h"
#include "ResultTableModelUtil.h"
#include "widgets/SqlCodePreview.h"
@ -27,7 +27,7 @@ CatalogTablesPage::CatalogTablesPage(std::shared_ptr<OpenDatabase> opendatabase,
: QSplitter(Qt::Horizontal, parent)
, m_tablesTableView(this, new TablesTableModel(opendatabase, this))
{
auto tv = m_tablesTableView.tableView();
auto tv = m_tablesTableView.itemView();
tv->setSelectionMode(QAbstractItemView::SingleSelection);
m_detailsTabs = new QTabWidget(this);
@ -106,7 +106,7 @@ void CatalogTablesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
void CatalogTablesPage::setNamespaceFilter(NamespaceFilter filter)
{
m_tablesTableView.dataModel()->setNamespaceFilter(filter);
m_tablesTableView.tableView()->resizeColumnsToContents();
//m_tablesTableView.tableView()->resizeColumnsToContents();
}
void CatalogTablesPage::tableListTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
@ -114,8 +114,8 @@ void CatalogTablesPage::tableListTable_currentRowChanged(const QModelIndex &curr
if (current.row() == previous.row())
return;
auto table = m_tablesTableView.rowItemForProxyIndex(current);
selectedTableChanged(table);
auto tableNode = TablesTableModel::nodeFromIndex(m_tablesTableView.sortFilter()->mapToSource(current)); // m_tablesTableView.rowItemForProxyIndex(current);
selectedTableChanged(tableNode->_class);
}
@ -127,11 +127,15 @@ void CatalogTablesPage::tableListTable_layoutChanged(const QList<QPersistentMode
void CatalogTablesPage::on_tableListTable_doubleClicked(const QModelIndex &index)
{
auto row = m_tablesTableView.sortFilter()->mapToSource(index).row();
PgClass table = m_tablesTableView.dataModel()->getTable(row);
if (table.oid() != InvalidOid) {
tableSelected(table.oid());
}
auto sourceIndex = m_tablesTableView.sortFilter()->mapToSource(index);
auto tableNode = TablesTableModel::nodeFromIndex(sourceIndex);
if (tableNode)
{
Oid oid = tableNode->_class.oid();
if (oid != InvalidOid) {
tableSelected(oid);
}
}
}
void CatalogTablesPage::selectedTableChanged(const std::optional<PgClass> &table)

View file

@ -2,13 +2,13 @@
#define CATALOGTABLESPAGE_H
#include "NamespaceFilter.h"
#include "catalog/models/TablesTableModel.h"
#include "catalog/tables/TablesTableModel.h"
#include "util/PgLabTableViewHelper.h"
#include <QSplitter>
#include <memory>
#include <optional>
#include <QAbstractItemModel>
#include "Pgsql_oids.h"
class CatalogConstraintPage;
class CatalogIndexPage;
@ -39,7 +39,7 @@ public:
signals:
void tableSelected(Oid tableoid);
private:
PgLabTableViewHelper<TablesTableModel> m_tablesTableView;
PgLabTableViewHelper<TablesTableModel, QTreeView> m_tablesTableView;
// Details
QTabWidget *m_detailsTabs = nullptr;

View file

@ -32,8 +32,8 @@ SOURCES += main.cpp\
catalog/models/ProcTableModel.cpp \
catalog/models/RolesTableModel.cpp \
catalog/models/SequenceModel.cpp \
catalog/models/TablesTableModel.cpp \
catalog/models/TriggerTableModel.cpp \
catalog/tables/TablesTableModel.cpp \
catalog/widgets/CatalogConstraintPage.cpp \
catalog/widgets/CatalogFunctionsPage.cpp \
catalog/widgets/CatalogIndexPage.cpp \
@ -104,8 +104,8 @@ HEADERS += \
catalog/models/ProcTableModel.h \
catalog/models/RolesTableModel.h \
catalog/models/SequenceModel.h \
catalog/models/TablesTableModel.h \
catalog/models/TriggerTableModel.h \
catalog/tables/TablesTableModel.h \
catalog/widgets/CatalogConstraintPage.h \
catalog/widgets/CatalogFunctionsPage.h \
catalog/widgets/CatalogIndexPage.h \

View file

@ -12,7 +12,7 @@ DatabasesPage::DatabasesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget
: QSplitter(Qt::Horizontal, parent)
, m_databasesTableView(this, new DatabasesTableModel(opendatabase, this))
{
auto tv = m_databasesTableView.tableView();
auto tv = m_databasesTableView.itemView();
tv->setSelectionMode(QAbstractItemView::SingleSelection);
tv->setContextMenuPolicy(Qt::ActionsContextMenu);
@ -23,7 +23,7 @@ DatabasesPage::DatabasesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget
m_tableSql = new SqlCodePreview(this);
addWidget(m_tableSql);
connect(m_databasesTableView.tableView()->selectionModel(), &QItemSelectionModel::currentRowChanged,
connect(m_databasesTableView.itemView()->selectionModel(), &QItemSelectionModel::currentRowChanged,
this, &DatabasesPage::databaseSelectionChanged);
connect(createDbAction, &QAction::triggered,
[this](auto checked)
@ -37,7 +37,7 @@ void DatabasesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
{
m_catalog = cat;
m_databasesTableView.dataModel()->setDatabaseList(cat);
m_databasesTableView.tableView()->resizeColumnsToContents();
m_databasesTableView.itemView()->resizeColumnsToContents();
}
void DatabasesPage::updateDatabaseDetails(const PgDatabase &db)

View file

@ -6,7 +6,7 @@ RolesPage::RolesPage(QWidget * parent)
: QSplitter(Qt::Horizontal, parent)
, m_rolesTableView(this)
{
auto tv = m_rolesTableView.tableView();
auto tv = m_rolesTableView.itemView();
tv->setSelectionMode(QAbstractItemView::SingleSelection);
m_detailsTabs = new QTabWidget(this);
@ -19,5 +19,5 @@ void RolesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
{
m_catalog = cat;
m_rolesTableView.dataModel()->setRoleList(cat->authIds());
m_rolesTableView.tableView()->resizeColumnsToContents();
m_rolesTableView.itemView()->resizeColumnsToContents();
}

View file

@ -135,7 +135,7 @@ void PgLabItemDelegate::initStyleOption(QStyleOptionViewItem *option,
suffix = "B";
forground_color = QColorConstants::Svg::darkblue;
}
option->text = QString{ "%1 %2" }.arg(val, 3, 'g', -1 ).arg(suffix) ;
option->text = QString{ "%1 %2" }.arg(val, 0, 'g', 3).arg(suffix) ;
}
else {
auto str = value.toString();

View file

@ -1,25 +1,51 @@
#pragma once
#include <QTableWidget>
#include <QTreeView>
#include <QSortFilterProxyModel>
#include "util/PgLabItemDelegate.h"
#include "util/PgLabTableView.h"
#include <optional>
class PgDatabaseCatalog;
template <typename TableModel>
template <typename ViewType>
void ResizeColumnsToContent(ViewType *vt)
{
vt->resizeColumnsToContents();
}
template <>
inline void ResizeColumnsToContent<QTreeView>(QTreeView *)
{
}
template <typename ViewType>
void InitView(ViewType *vt)
{}
template <>
inline void InitView<QTreeView>(QTreeView *tv)
{
tv->setAlternatingRowColors(true);
tv->setItemDelegate(new PgLabItemDelegate(tv));
tv->setWordWrap(false);
}
template <typename TableModel, typename ViewType = PgLabTableView>
class PgLabTableViewHelper {
public:
PgLabTableViewHelper(QWidget * parent, TableModel *tableModel)
{
m_tableView = new PgLabTableView(parent);
m_itemView = new ViewType(parent);
InitView(m_itemView);
m_dataModel = tableModel;
m_sortFilter = new QSortFilterProxyModel(parent);
m_sortFilter->setSourceModel(m_dataModel);
m_tableView->setModel(m_sortFilter);
m_tableView->setSortingEnabled(true);
m_itemView->setModel(m_sortFilter);
m_itemView->setSortingEnabled(true);
m_sortFilter->sort(0, Qt::AscendingOrder);
}
@ -27,9 +53,9 @@ public:
: PgLabTableViewHelper(parent, new TableModel(parent))
{}
PgLabTableView *tableView() const
ViewType *itemView() const
{
return m_tableView;
return m_itemView;
}
TableModel *dataModel() const
@ -45,27 +71,27 @@ public:
void setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
{
m_dataModel->setCatalog(cat);
m_tableView->resizeColumnsToContents();
ResizeColumnsToContent(m_itemView);
}
QModelIndex currentSourceIndex() const
{
QModelIndex index = m_tableView->selectionModel()->currentIndex();
QModelIndex index = m_itemView->selectionModel()->currentIndex();
if (!index.isValid())
return index;
return m_sortFilter->mapToSource(index);
}
typename TableModel::RowItem rowItemForSourceRow(int row) const
typename TableModel::RowItem rowItemForSourceRow(QModelIndex index) const
{
return m_dataModel->rowItem(row);
return m_dataModel->rowItem(index);
}
typename TableModel::RowItem rowItemForProxyIndex(QModelIndex index)
{
QModelIndex sourceIndex = m_sortFilter->mapToSource(index);
return m_dataModel->rowItem(sourceIndex.row());
return m_dataModel->rowItem(sourceIndex);
}
typename TableModel::RowItem rowItemForProxyRow(int row) const
@ -79,12 +105,12 @@ public:
if (!index.isValid())
return {};
return rowItemForSourceRow(index.row());
return rowItemForSourceRow(index);
}
private:
PgLabTableView *m_tableView = nullptr;
ViewType *m_itemView = nullptr;
TableModel *m_dataModel = nullptr;
QSortFilterProxyModel *m_sortFilter = nullptr;
};