The table inheritance works mostly
This commit is contained in:
parent
ccd88d0578
commit
2ff9577d41
22 changed files with 473 additions and 145 deletions
|
|
@ -38,9 +38,9 @@ public:
|
||||||
virtual Oid getType(int column) const override;
|
virtual Oid getType(int column) const override;
|
||||||
virtual QVariant getData(const QModelIndex &index) 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:
|
protected:
|
||||||
virtual QVariant getDataMeaning(const QModelIndex &index) const override;
|
virtual QVariant getDataMeaning(const QModelIndex &index) const override;
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,16 @@
|
||||||
#include "catalog/PgClass.h"
|
#include "catalog/PgClass.h"
|
||||||
#include "catalog/PgClassContainer.h"
|
#include "catalog/PgClassContainer.h"
|
||||||
#include "catalog/PgNamespace.h"
|
#include "catalog/PgNamespace.h"
|
||||||
#include "catalog/PgNamespaceContainer.h"
|
#include "catalog/PgInheritsContainer.h"
|
||||||
#include "Pgsql_declare.h"
|
//#include "Pgsql_declare.h"
|
||||||
|
#include "ui/catalog/tables/TableTreeBuilder.h"
|
||||||
#include "CustomDataRole.h"
|
#include "CustomDataRole.h"
|
||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
#include "Pgsql_Connection.h"
|
#include "Pgsql_Connection.h"
|
||||||
|
|
||||||
TablesTableModel::TablesTableModel(std::shared_ptr<OpenDatabase> opendatabase, QObject *parent)
|
TablesTableModel::TablesTableModel(std::shared_ptr<OpenDatabase> opendatabase, QObject *parent)
|
||||||
: QAbstractTableModel(parent)
|
: QAbstractItemModel(parent)
|
||||||
, openDatabase(opendatabase)
|
, openDatabase(opendatabase)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
@ -36,17 +37,18 @@ void TablesTableModel::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
|
||||||
bool TableLike(RelKind relkind)
|
bool TableLike(RelKind relkind)
|
||||||
{
|
{
|
||||||
switch (relkind) {
|
switch (relkind) {
|
||||||
case RelKind::Table:
|
case RelKind::Table:
|
||||||
case RelKind::View:
|
case RelKind::View:
|
||||||
case RelKind::MaterializedView:
|
case RelKind::MaterializedView:
|
||||||
case RelKind::ForeignTable:
|
case RelKind::ForeignTable:
|
||||||
case RelKind::PartitionedTable:
|
case RelKind::PartitionedTable:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TablesTableModel::refresh()
|
void TablesTableModel::refresh()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|
@ -55,31 +57,19 @@ void TablesTableModel::refresh()
|
||||||
if (!m_catalog)
|
if (!m_catalog)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Later afscheiden naar filter functie
|
|
||||||
auto classes = m_catalog->classes();
|
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));
|
StartLoadTableSizes(std::move(oidIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,14 +96,46 @@ QVariant TablesTableModel::headerData(int section, Qt::Orientation orientation,
|
||||||
return QVariant();
|
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
|
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
|
Oid TablesTableModel::getType(int column) const
|
||||||
|
|
@ -142,37 +164,29 @@ Oid TablesTableModel::getType(int column) const
|
||||||
|
|
||||||
QVariant TablesTableModel::getData(const QModelIndex &index) const
|
QVariant TablesTableModel::getData(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
const auto &table = m_tables[index.row()];
|
// const auto &table = rootNode->children[index.row()];
|
||||||
const auto &t = table._class;
|
const TableNode* table = nodeFromIndex(index);
|
||||||
const auto &s = table.sizes;
|
const auto &t = table->_class;
|
||||||
|
const auto &s = table->sizes;
|
||||||
|
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case NameCol: return t.objectName();
|
case NameCol: return t.objectName();
|
||||||
case NamespaceCol: return t.nsName();
|
case NamespaceCol: return t.nsName();
|
||||||
case KindCol: return t.typeName();
|
case KindCol: return t.typeName();
|
||||||
case OwnerCol: return t.ownerName();
|
case OwnerCol: return t.ownerName();
|
||||||
case TablespaceCol: return getTablespaceDisplayString(*m_catalog, t.tablespace);
|
case TablespaceCol: return getTablespaceDisplayString(*m_catalog, t.tablespace);
|
||||||
case OptionsCol: break;
|
case OptionsCol: break;
|
||||||
case AclCol: return t.aclString();
|
case AclCol: return t.aclString();
|
||||||
case CommentCol: return t.description;
|
case CommentCol: return t.description;
|
||||||
case TotalSizeCol: return s.oid == 0 ? QVariant() : s.totalBytes;
|
case TotalSizeCol: return s.oid == 0 ? QVariant() : s.totalBytes;
|
||||||
case TableSizeCol: return s.oid == 0 ? QVariant() : s.totalBytes - s.indexBytes - s.toastBytes;
|
case TableSizeCol: return s.oid == 0 ? QVariant() : s.totalBytes - s.indexBytes - s.toastBytes;
|
||||||
case IndexSizeCol: return s.oid == 0 ? QVariant() : s.indexBytes;
|
case IndexSizeCol: return s.oid == 0 ? QVariant() : s.indexBytes;
|
||||||
case ToastSizeCol: return s.oid == 0 ? QVariant() : s.toastBytes;
|
case ToastSizeCol: return s.oid == 0 ? QVariant() : s.toastBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
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
|
QVariant TablesTableModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (role == Qt::DisplayRole)
|
if (role == Qt::DisplayRole)
|
||||||
|
|
@ -195,7 +209,7 @@ QVariant TablesTableModel::data(const QModelIndex &index, int role) const
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TablesTableModel::StartLoadTableSizes(std::map<Oid, int> oidIndex)
|
void TablesTableModel::StartLoadTableSizes(OidClassIndex oidIndex)
|
||||||
{
|
{
|
||||||
QPointer p(this);
|
QPointer p(this);
|
||||||
QtConcurrent::run([this]
|
QtConcurrent::run([this]
|
||||||
|
|
@ -205,7 +219,7 @@ void TablesTableModel::StartLoadTableSizes(std::map<Oid, int> oidIndex)
|
||||||
.then(qApp, [p, oidIndex] (TableSizes sizes)
|
.then(qApp, [p, oidIndex] (TableSizes sizes)
|
||||||
{
|
{
|
||||||
if (p)
|
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;
|
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)
|
for (auto s : sizes)
|
||||||
{
|
{
|
||||||
auto findIter = oidIndex.find(s.oid);
|
auto findIter = oidIndex.find(s.oid);
|
||||||
if (findIter != oidIndex.end())
|
if (findIter != oidIndex.end())
|
||||||
{
|
{
|
||||||
m_tables[findIter->second].sizes = s;
|
findIter->second->sizes = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit dataChanged(
|
emit dataChanged(
|
||||||
createIndex(0, TotalSizeCol),
|
index(0, TotalSizeCol),
|
||||||
createIndex(static_cast<int>(m_tables.size()), ToastSizeCol)
|
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"; };
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
#ifndef TABLESTABLEMODEL_H
|
#ifndef TABLESTABLEMODEL_H
|
||||||
#define 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 "NamespaceFilter.h"
|
||||||
#include "catalog/PgClass.h"
|
#include "catalog/PgClass.h"
|
||||||
|
#include <QAbstractItemModel>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -11,7 +14,7 @@ class OpenDatabase;
|
||||||
class PgClass;
|
class PgClass;
|
||||||
class PgDatabaseCatalog;
|
class PgDatabaseCatalog;
|
||||||
|
|
||||||
class TablesTableModel: public QAbstractTableModel {
|
class TablesTableModel: public QAbstractItemModel {
|
||||||
public:
|
public:
|
||||||
using RowItem = PgClass;
|
using RowItem = PgClass;
|
||||||
enum e_Columns : int {
|
enum e_Columns : int {
|
||||||
|
|
@ -40,42 +43,31 @@ public:
|
||||||
int rowCount(const QModelIndex &parent) const override;
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
int columnCount(const QModelIndex &parent) const override;
|
int columnCount(const QModelIndex &parent) const override;
|
||||||
|
|
||||||
virtual QVariant data(const QModelIndex &index, int role) const override;
|
QModelIndex index(int row, int column,
|
||||||
PgClass getTable(int row) const;
|
const QModelIndex &parent = QModelIndex()) const override;
|
||||||
RowItem rowItem(int row) const
|
|
||||||
|
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:
|
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>;
|
using TableSizes = std::vector<TableSize>;
|
||||||
|
|
||||||
class Table {
|
// this is a readonly model so when the vectors have been filled
|
||||||
public:
|
// they will not change anymore and it is safe to assume the indexes
|
||||||
PgClass _class;
|
// of elements do not change
|
||||||
TableSize sizes;
|
|
||||||
|
|
||||||
Table(const PgClass &cls)
|
|
||||||
: _class(cls)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
using t_Tables = std::vector<Table>;
|
|
||||||
|
|
||||||
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
|
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
|
||||||
NamespaceFilter m_namespaceFilter = NamespaceFilter::User;
|
NamespaceFilter m_namespaceFilter = NamespaceFilter::User;
|
||||||
t_Tables m_tables;
|
std::shared_ptr<TableNode> rootNode;
|
||||||
QMetaObject::Connection refreshConnection;
|
QMetaObject::Connection refreshConnection;
|
||||||
std::shared_ptr<OpenDatabase> openDatabase;
|
std::shared_ptr<OpenDatabase> openDatabase;
|
||||||
|
|
||||||
|
|
@ -83,10 +75,17 @@ private:
|
||||||
Oid getType(int column) const;
|
Oid getType(int column) const;
|
||||||
QVariant getData(const QModelIndex &index) const;
|
QVariant getData(const QModelIndex &index) const;
|
||||||
|
|
||||||
void StartLoadTableSizes(std::map<Oid, int> oidIndex);
|
using OidClassIndex = std::map<Oid, std::shared_ptr<TableNode>>;
|
||||||
TableSizes QueryTableSizes() const;
|
|
||||||
void PopulateSizes(std::map<Oid, int> oidIndex, std::vector<TableSize> sizes);
|
|
||||||
|
|
||||||
|
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:
|
private slots:
|
||||||
void refresh();
|
void refresh();
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#include "catalog/widgets/TriggerPage.h"
|
#include "catalog/widgets/TriggerPage.h"
|
||||||
#include "catalog/models/ColumnTableModel.h"
|
#include "catalog/models/ColumnTableModel.h"
|
||||||
#include "catalog/models/ConstraintModel.h"
|
#include "catalog/models/ConstraintModel.h"
|
||||||
#include "catalog/models/TablesTableModel.h"
|
#include "catalog/tables/TablesTableModel.h"
|
||||||
#include "util/PgLabTableView.h"
|
#include "util/PgLabTableView.h"
|
||||||
#include "ResultTableModelUtil.h"
|
#include "ResultTableModelUtil.h"
|
||||||
#include "widgets/SqlCodePreview.h"
|
#include "widgets/SqlCodePreview.h"
|
||||||
|
|
@ -27,7 +27,7 @@ CatalogTablesPage::CatalogTablesPage(std::shared_ptr<OpenDatabase> opendatabase,
|
||||||
: QSplitter(Qt::Horizontal, parent)
|
: QSplitter(Qt::Horizontal, parent)
|
||||||
, m_tablesTableView(this, new TablesTableModel(opendatabase, this))
|
, m_tablesTableView(this, new TablesTableModel(opendatabase, this))
|
||||||
{
|
{
|
||||||
auto tv = m_tablesTableView.tableView();
|
auto tv = m_tablesTableView.itemView();
|
||||||
tv->setSelectionMode(QAbstractItemView::SingleSelection);
|
tv->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
m_detailsTabs = new QTabWidget(this);
|
m_detailsTabs = new QTabWidget(this);
|
||||||
|
|
||||||
|
|
@ -106,7 +106,7 @@ void CatalogTablesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
|
||||||
void CatalogTablesPage::setNamespaceFilter(NamespaceFilter filter)
|
void CatalogTablesPage::setNamespaceFilter(NamespaceFilter filter)
|
||||||
{
|
{
|
||||||
m_tablesTableView.dataModel()->setNamespaceFilter(filter);
|
m_tablesTableView.dataModel()->setNamespaceFilter(filter);
|
||||||
m_tablesTableView.tableView()->resizeColumnsToContents();
|
//m_tablesTableView.tableView()->resizeColumnsToContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CatalogTablesPage::tableListTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
void CatalogTablesPage::tableListTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
||||||
|
|
@ -114,8 +114,8 @@ void CatalogTablesPage::tableListTable_currentRowChanged(const QModelIndex &curr
|
||||||
if (current.row() == previous.row())
|
if (current.row() == previous.row())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto table = m_tablesTableView.rowItemForProxyIndex(current);
|
auto tableNode = TablesTableModel::nodeFromIndex(m_tablesTableView.sortFilter()->mapToSource(current)); // m_tablesTableView.rowItemForProxyIndex(current);
|
||||||
selectedTableChanged(table);
|
selectedTableChanged(tableNode->_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -127,11 +127,15 @@ void CatalogTablesPage::tableListTable_layoutChanged(const QList<QPersistentMode
|
||||||
|
|
||||||
void CatalogTablesPage::on_tableListTable_doubleClicked(const QModelIndex &index)
|
void CatalogTablesPage::on_tableListTable_doubleClicked(const QModelIndex &index)
|
||||||
{
|
{
|
||||||
auto row = m_tablesTableView.sortFilter()->mapToSource(index).row();
|
auto sourceIndex = m_tablesTableView.sortFilter()->mapToSource(index);
|
||||||
PgClass table = m_tablesTableView.dataModel()->getTable(row);
|
auto tableNode = TablesTableModel::nodeFromIndex(sourceIndex);
|
||||||
if (table.oid() != InvalidOid) {
|
if (tableNode)
|
||||||
tableSelected(table.oid());
|
{
|
||||||
}
|
Oid oid = tableNode->_class.oid();
|
||||||
|
if (oid != InvalidOid) {
|
||||||
|
tableSelected(oid);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CatalogTablesPage::selectedTableChanged(const std::optional<PgClass> &table)
|
void CatalogTablesPage::selectedTableChanged(const std::optional<PgClass> &table)
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
#define CATALOGTABLESPAGE_H
|
#define CATALOGTABLESPAGE_H
|
||||||
|
|
||||||
#include "NamespaceFilter.h"
|
#include "NamespaceFilter.h"
|
||||||
#include "catalog/models/TablesTableModel.h"
|
#include "catalog/tables/TablesTableModel.h"
|
||||||
#include "util/PgLabTableViewHelper.h"
|
#include "util/PgLabTableViewHelper.h"
|
||||||
#include <QSplitter>
|
#include <QSplitter>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include "Pgsql_oids.h"
|
|
||||||
|
|
||||||
class CatalogConstraintPage;
|
class CatalogConstraintPage;
|
||||||
class CatalogIndexPage;
|
class CatalogIndexPage;
|
||||||
|
|
@ -39,7 +39,7 @@ public:
|
||||||
signals:
|
signals:
|
||||||
void tableSelected(Oid tableoid);
|
void tableSelected(Oid tableoid);
|
||||||
private:
|
private:
|
||||||
PgLabTableViewHelper<TablesTableModel> m_tablesTableView;
|
PgLabTableViewHelper<TablesTableModel, QTreeView> m_tablesTableView;
|
||||||
|
|
||||||
// Details
|
// Details
|
||||||
QTabWidget *m_detailsTabs = nullptr;
|
QTabWidget *m_detailsTabs = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@ SOURCES += main.cpp\
|
||||||
catalog/models/ProcTableModel.cpp \
|
catalog/models/ProcTableModel.cpp \
|
||||||
catalog/models/RolesTableModel.cpp \
|
catalog/models/RolesTableModel.cpp \
|
||||||
catalog/models/SequenceModel.cpp \
|
catalog/models/SequenceModel.cpp \
|
||||||
catalog/models/TablesTableModel.cpp \
|
|
||||||
catalog/models/TriggerTableModel.cpp \
|
catalog/models/TriggerTableModel.cpp \
|
||||||
|
catalog/tables/TablesTableModel.cpp \
|
||||||
catalog/widgets/CatalogConstraintPage.cpp \
|
catalog/widgets/CatalogConstraintPage.cpp \
|
||||||
catalog/widgets/CatalogFunctionsPage.cpp \
|
catalog/widgets/CatalogFunctionsPage.cpp \
|
||||||
catalog/widgets/CatalogIndexPage.cpp \
|
catalog/widgets/CatalogIndexPage.cpp \
|
||||||
|
|
@ -104,8 +104,8 @@ HEADERS += \
|
||||||
catalog/models/ProcTableModel.h \
|
catalog/models/ProcTableModel.h \
|
||||||
catalog/models/RolesTableModel.h \
|
catalog/models/RolesTableModel.h \
|
||||||
catalog/models/SequenceModel.h \
|
catalog/models/SequenceModel.h \
|
||||||
catalog/models/TablesTableModel.h \
|
|
||||||
catalog/models/TriggerTableModel.h \
|
catalog/models/TriggerTableModel.h \
|
||||||
|
catalog/tables/TablesTableModel.h \
|
||||||
catalog/widgets/CatalogConstraintPage.h \
|
catalog/widgets/CatalogConstraintPage.h \
|
||||||
catalog/widgets/CatalogFunctionsPage.h \
|
catalog/widgets/CatalogFunctionsPage.h \
|
||||||
catalog/widgets/CatalogIndexPage.h \
|
catalog/widgets/CatalogIndexPage.h \
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ DatabasesPage::DatabasesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget
|
||||||
: QSplitter(Qt::Horizontal, parent)
|
: QSplitter(Qt::Horizontal, parent)
|
||||||
, m_databasesTableView(this, new DatabasesTableModel(opendatabase, this))
|
, m_databasesTableView(this, new DatabasesTableModel(opendatabase, this))
|
||||||
{
|
{
|
||||||
auto tv = m_databasesTableView.tableView();
|
auto tv = m_databasesTableView.itemView();
|
||||||
tv->setSelectionMode(QAbstractItemView::SingleSelection);
|
tv->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
tv->setContextMenuPolicy(Qt::ActionsContextMenu);
|
tv->setContextMenuPolicy(Qt::ActionsContextMenu);
|
||||||
|
|
||||||
|
|
@ -23,7 +23,7 @@ DatabasesPage::DatabasesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget
|
||||||
m_tableSql = new SqlCodePreview(this);
|
m_tableSql = new SqlCodePreview(this);
|
||||||
addWidget(m_tableSql);
|
addWidget(m_tableSql);
|
||||||
|
|
||||||
connect(m_databasesTableView.tableView()->selectionModel(), &QItemSelectionModel::currentRowChanged,
|
connect(m_databasesTableView.itemView()->selectionModel(), &QItemSelectionModel::currentRowChanged,
|
||||||
this, &DatabasesPage::databaseSelectionChanged);
|
this, &DatabasesPage::databaseSelectionChanged);
|
||||||
connect(createDbAction, &QAction::triggered,
|
connect(createDbAction, &QAction::triggered,
|
||||||
[this](auto checked)
|
[this](auto checked)
|
||||||
|
|
@ -37,7 +37,7 @@ void DatabasesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
|
||||||
{
|
{
|
||||||
m_catalog = cat;
|
m_catalog = cat;
|
||||||
m_databasesTableView.dataModel()->setDatabaseList(cat);
|
m_databasesTableView.dataModel()->setDatabaseList(cat);
|
||||||
m_databasesTableView.tableView()->resizeColumnsToContents();
|
m_databasesTableView.itemView()->resizeColumnsToContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabasesPage::updateDatabaseDetails(const PgDatabase &db)
|
void DatabasesPage::updateDatabaseDetails(const PgDatabase &db)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ RolesPage::RolesPage(QWidget * parent)
|
||||||
: QSplitter(Qt::Horizontal, parent)
|
: QSplitter(Qt::Horizontal, parent)
|
||||||
, m_rolesTableView(this)
|
, m_rolesTableView(this)
|
||||||
{
|
{
|
||||||
auto tv = m_rolesTableView.tableView();
|
auto tv = m_rolesTableView.itemView();
|
||||||
tv->setSelectionMode(QAbstractItemView::SingleSelection);
|
tv->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
|
||||||
m_detailsTabs = new QTabWidget(this);
|
m_detailsTabs = new QTabWidget(this);
|
||||||
|
|
@ -19,5 +19,5 @@ void RolesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
|
||||||
{
|
{
|
||||||
m_catalog = cat;
|
m_catalog = cat;
|
||||||
m_rolesTableView.dataModel()->setRoleList(cat->authIds());
|
m_rolesTableView.dataModel()->setRoleList(cat->authIds());
|
||||||
m_rolesTableView.tableView()->resizeColumnsToContents();
|
m_rolesTableView.itemView()->resizeColumnsToContents();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ void PgLabItemDelegate::initStyleOption(QStyleOptionViewItem *option,
|
||||||
suffix = "B";
|
suffix = "B";
|
||||||
forground_color = QColorConstants::Svg::darkblue;
|
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 {
|
else {
|
||||||
auto str = value.toString();
|
auto str = value.toString();
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,51 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QTableWidget>
|
#include <QTableWidget>
|
||||||
|
#include <QTreeView>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
#include "util/PgLabItemDelegate.h"
|
||||||
#include "util/PgLabTableView.h"
|
#include "util/PgLabTableView.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
class PgDatabaseCatalog;
|
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 {
|
class PgLabTableViewHelper {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PgLabTableViewHelper(QWidget * parent, TableModel *tableModel)
|
PgLabTableViewHelper(QWidget * parent, TableModel *tableModel)
|
||||||
{
|
{
|
||||||
m_tableView = new PgLabTableView(parent);
|
m_itemView = new ViewType(parent);
|
||||||
|
InitView(m_itemView);
|
||||||
m_dataModel = tableModel;
|
m_dataModel = tableModel;
|
||||||
m_sortFilter = new QSortFilterProxyModel(parent);
|
m_sortFilter = new QSortFilterProxyModel(parent);
|
||||||
m_sortFilter->setSourceModel(m_dataModel);
|
m_sortFilter->setSourceModel(m_dataModel);
|
||||||
m_tableView->setModel(m_sortFilter);
|
m_itemView->setModel(m_sortFilter);
|
||||||
m_tableView->setSortingEnabled(true);
|
m_itemView->setSortingEnabled(true);
|
||||||
m_sortFilter->sort(0, Qt::AscendingOrder);
|
m_sortFilter->sort(0, Qt::AscendingOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,9 +53,9 @@ public:
|
||||||
: PgLabTableViewHelper(parent, new TableModel(parent))
|
: PgLabTableViewHelper(parent, new TableModel(parent))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
PgLabTableView *tableView() const
|
ViewType *itemView() const
|
||||||
{
|
{
|
||||||
return m_tableView;
|
return m_itemView;
|
||||||
}
|
}
|
||||||
|
|
||||||
TableModel *dataModel() const
|
TableModel *dataModel() const
|
||||||
|
|
@ -45,27 +71,27 @@ public:
|
||||||
void setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
|
void setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
|
||||||
{
|
{
|
||||||
m_dataModel->setCatalog(cat);
|
m_dataModel->setCatalog(cat);
|
||||||
m_tableView->resizeColumnsToContents();
|
ResizeColumnsToContent(m_itemView);
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex currentSourceIndex() const
|
QModelIndex currentSourceIndex() const
|
||||||
{
|
{
|
||||||
QModelIndex index = m_tableView->selectionModel()->currentIndex();
|
QModelIndex index = m_itemView->selectionModel()->currentIndex();
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return index;
|
return index;
|
||||||
|
|
||||||
return m_sortFilter->mapToSource(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)
|
typename TableModel::RowItem rowItemForProxyIndex(QModelIndex index)
|
||||||
{
|
{
|
||||||
QModelIndex sourceIndex = m_sortFilter->mapToSource(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
|
typename TableModel::RowItem rowItemForProxyRow(int row) const
|
||||||
|
|
@ -79,12 +105,12 @@ public:
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return rowItemForSourceRow(index.row());
|
return rowItemForSourceRow(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PgLabTableView *m_tableView = nullptr;
|
ViewType *m_itemView = nullptr;
|
||||||
TableModel *m_dataModel = nullptr;
|
TableModel *m_dataModel = nullptr;
|
||||||
QSortFilterProxyModel *m_sortFilter = nullptr;
|
QSortFilterProxyModel *m_sortFilter = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,24 @@
|
||||||
|
|
||||||
#include "PgContainer.h"
|
#include "PgContainer.h"
|
||||||
#include "PgInherits.h"
|
#include "PgInherits.h"
|
||||||
#include "Pgsql_declare.h"
|
|
||||||
|
|
||||||
|
class IFindParents
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual std::vector<Oid> getParentsOf(Oid oid) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class PgInheritsContainer : public PgContainer<PgInherits, PgInherits::Key> {
|
class PgInheritsContainer
|
||||||
|
: public PgContainer<PgInherits, PgInherits::Key>
|
||||||
|
, public IFindParents
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
using PgContainer<PgInherits, PgInherits::Key>::PgContainer;
|
using PgContainer<PgInherits, PgInherits::Key>::PgContainer;
|
||||||
|
|
||||||
virtual std::string getLoadQuery() const override;
|
virtual std::string getLoadQuery() const override;
|
||||||
|
|
||||||
/// Returns the parents in the correct order
|
/// Returns the parents in the correct order
|
||||||
std::vector<Oid> getParentsOf(Oid oid) const;
|
std::vector<Oid> getParentsOf(Oid oid) const override;
|
||||||
protected:
|
protected:
|
||||||
PgInherits loadElem(const Pgsql::Row &row) override;
|
PgInherits loadElem(const Pgsql::Row &row) override;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,9 @@ SOURCES += \
|
||||||
catalog/PgConstraintContainer.cpp \
|
catalog/PgConstraintContainer.cpp \
|
||||||
ParamListJson.cpp \
|
ParamListJson.cpp \
|
||||||
ParamListModel.cpp \
|
ParamListModel.cpp \
|
||||||
|
ui/catalog/tables/TableNode.cpp \
|
||||||
|
ui/catalog/tables/TableSize.cpp \
|
||||||
|
ui/catalog/tables/TableTreeBuilder.cpp \
|
||||||
util.cpp \
|
util.cpp \
|
||||||
SqlFormattingUtils.cpp \
|
SqlFormattingUtils.cpp \
|
||||||
catalog/PgKeywordList.cpp \
|
catalog/PgKeywordList.cpp \
|
||||||
|
|
@ -113,6 +116,9 @@ HEADERS += \
|
||||||
catalog/PgConstraintContainer.h \
|
catalog/PgConstraintContainer.h \
|
||||||
ParamListJson.h \
|
ParamListJson.h \
|
||||||
ParamListModel.h \
|
ParamListModel.h \
|
||||||
|
ui/catalog/tables/TableNode.h \
|
||||||
|
ui/catalog/tables/TableSize.h \
|
||||||
|
ui/catalog/tables/TableTreeBuilder.h \
|
||||||
util.h \
|
util.h \
|
||||||
SqlFormattingUtils.h \
|
SqlFormattingUtils.h \
|
||||||
catalog/PgCatalogTypes.h \
|
catalog/PgCatalogTypes.h \
|
||||||
|
|
|
||||||
20
pglablib/ui/catalog/tables/TableNode.cpp
Normal file
20
pglablib/ui/catalog/tables/TableNode.cpp
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
#include "TableNode.h"
|
||||||
|
#include "catalog/PgDatabaseCatalog.h"
|
||||||
|
namespace {
|
||||||
|
PgDatabaseCatalog dummyCatalog;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableNode::TableNode()
|
||||||
|
: _class(dummyCatalog, InvalidOid, "", InvalidOid)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TableNode::TableNode(const PgClass &cls)
|
||||||
|
: _class(cls)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const TableNode *TableNode::getChildPtr(int index) const
|
||||||
|
{
|
||||||
|
return children.at(index).get();
|
||||||
|
}
|
||||||
25
pglablib/ui/catalog/tables/TableNode.h
Normal file
25
pglablib/ui/catalog/tables/TableNode.h
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "TableSize.h"
|
||||||
|
#include "catalog/PgClass.h"
|
||||||
|
|
||||||
|
class TableNode;
|
||||||
|
using t_Tables = std::vector<std::shared_ptr<TableNode>>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TableNode {
|
||||||
|
public:
|
||||||
|
PgClass _class;
|
||||||
|
TableSize sizes;
|
||||||
|
|
||||||
|
int myIndex;
|
||||||
|
std::weak_ptr<TableNode> parent; // hope we do not need it (must be weak to prevent circular reference)
|
||||||
|
t_Tables children;
|
||||||
|
|
||||||
|
TableNode();
|
||||||
|
TableNode(const PgClass &cls);
|
||||||
|
|
||||||
|
const TableNode* getChildPtr(int index) const;
|
||||||
|
};
|
||||||
6
pglablib/ui/catalog/tables/TableSize.cpp
Normal file
6
pglablib/ui/catalog/tables/TableSize.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include "TableSize.h"
|
||||||
|
|
||||||
|
|
||||||
|
TableSize::TableSize()
|
||||||
|
: oid(0)
|
||||||
|
{}
|
||||||
13
pglablib/ui/catalog/tables/TableSize.h
Normal file
13
pglablib/ui/catalog/tables/TableSize.h
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class TableSize {
|
||||||
|
public:
|
||||||
|
int oid;
|
||||||
|
int64_t totalBytes = -1;
|
||||||
|
int64_t indexBytes = -1;
|
||||||
|
int64_t toastBytes = -1;
|
||||||
|
|
||||||
|
TableSize();
|
||||||
|
};
|
||||||
82
pglablib/ui/catalog/tables/TableTreeBuilder.cpp
Normal file
82
pglablib/ui/catalog/tables/TableTreeBuilder.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
#include "TableTreeBuilder.h"
|
||||||
|
#include "catalog/PgInheritsContainer.h"
|
||||||
|
#include "TableNode.h"
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
|
TableTreeBuilder::TableTreeBuilder(
|
||||||
|
const std::map<Oid, PgClass> &source,
|
||||||
|
const IFindParents &inheritance
|
||||||
|
)
|
||||||
|
: source(source)
|
||||||
|
, inheritance(inheritance)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<std::shared_ptr<TableNode>, std::map<Oid, std::shared_ptr<TableNode>>> TableTreeBuilder::Build()
|
||||||
|
{
|
||||||
|
rootNode = std::make_shared<TableNode>();
|
||||||
|
|
||||||
|
// when childrens are ordered before there parents
|
||||||
|
// the parent will automatically be added first (recursively)
|
||||||
|
// processed nodes are tracked in the nodes member
|
||||||
|
for (auto && e : source | std::views::filter(
|
||||||
|
[this] (auto &e)
|
||||||
|
{
|
||||||
|
return processedNodes.count(e.first) == 0;
|
||||||
|
})
|
||||||
|
)
|
||||||
|
{
|
||||||
|
addNode(e.second);
|
||||||
|
}
|
||||||
|
AssignNodeIndexesAndParents(rootNode);
|
||||||
|
return { rootNode, std::move(processedNodes) };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<TableNode> TableTreeBuilder::addNode(const PgClass &cls)
|
||||||
|
{
|
||||||
|
std::shared_ptr<TableNode> node = std::make_shared<TableNode>(cls);
|
||||||
|
processedNodes.emplace(cls.oid(), node);
|
||||||
|
std::vector<Oid> parents = inheritance.getParentsOf(cls.oid());
|
||||||
|
if (parents.empty())
|
||||||
|
addToToplevel(node);
|
||||||
|
else
|
||||||
|
addToParents(node, parents);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableTreeBuilder::addToToplevel(std::shared_ptr<TableNode> node)
|
||||||
|
{
|
||||||
|
rootNode->children.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableTreeBuilder::addToParents(std::shared_ptr<TableNode> node, const std::vector<Oid> &parents)
|
||||||
|
{
|
||||||
|
for (auto &parent : parents)
|
||||||
|
{
|
||||||
|
getParent(parent)->children.push_back(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<TableNode> TableTreeBuilder::getParent(Oid oid)
|
||||||
|
{
|
||||||
|
auto parent = processedNodes.find(oid);
|
||||||
|
if (parent != processedNodes.end())
|
||||||
|
return parent->second;
|
||||||
|
|
||||||
|
// Not present, find in source list and add now
|
||||||
|
auto source_iter = source.find(oid);
|
||||||
|
assert(source_iter != source.end());
|
||||||
|
return addNode(source_iter->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableTreeBuilder::AssignNodeIndexesAndParents(std::shared_ptr<TableNode> parent)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
for (auto &n : parent->children)
|
||||||
|
{
|
||||||
|
n->parent = parent;
|
||||||
|
n->myIndex = index++;
|
||||||
|
AssignNodeIndexesAndParents(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
31
pglablib/ui/catalog/tables/TableTreeBuilder.h
Normal file
31
pglablib/ui/catalog/tables/TableTreeBuilder.h
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Pgsql_oids.h"
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class PgClass;
|
||||||
|
class TableNode;
|
||||||
|
class IFindParents;
|
||||||
|
|
||||||
|
class TableTreeBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TableTreeBuilder(const std::map<Oid, PgClass> &source, const IFindParents &inheritance);
|
||||||
|
|
||||||
|
std::tuple<std::shared_ptr<TableNode>, std::map<Oid, std::shared_ptr<TableNode>>> Build();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::map<Oid, PgClass> &source;
|
||||||
|
const IFindParents &inheritance;
|
||||||
|
std::map<Oid, std::shared_ptr<TableNode>> processedNodes;
|
||||||
|
std::shared_ptr<TableNode> rootNode;
|
||||||
|
|
||||||
|
bool hasParent(const PgClass &cls) const;
|
||||||
|
std::shared_ptr<TableNode> addNode(const PgClass &cls);
|
||||||
|
void addToToplevel(std::shared_ptr<TableNode> node);
|
||||||
|
void addToParents(std::shared_ptr<TableNode> node, const std::vector<Oid> &parents);
|
||||||
|
std::shared_ptr<TableNode> getParent(Oid oid);
|
||||||
|
void AssignNodeIndexesAndParents(std::shared_ptr<TableNode> parent);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -25,21 +25,21 @@ namespace Pgsql {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const ResultConstIterator &rhs)
|
bool operator==(const ResultConstIterator &rhs) const
|
||||||
{
|
{
|
||||||
return m_row == rhs.m_row;
|
return m_row == rhs.m_row;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const ResultConstIterator &rhs)
|
bool operator!=(const ResultConstIterator &rhs) const
|
||||||
{
|
{
|
||||||
return !operator==(rhs);
|
return !operator==(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Row& operator*()
|
const Row& operator*() const
|
||||||
{
|
{
|
||||||
return m_row;
|
return m_row;
|
||||||
}
|
}
|
||||||
const Row& operator->()
|
const Row& operator->() const
|
||||||
{
|
{
|
||||||
return m_row;
|
return m_row;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
7
releasenotes/notes/tabletree-efb590181a614167.yaml
Normal file
7
releasenotes/notes/tabletree-efb590181a614167.yaml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
The tables are now listed in a treeview. Tables that inherit from another
|
||||||
|
table or that are a partition of a partitioned table are now listed as subnodes
|
||||||
|
of their parents. A table that inherits more then one table is listed under
|
||||||
|
eacht of its parents.
|
||||||
64
tests/pglabtests/TableTreeBuilderTests.cpp
Normal file
64
tests/pglabtests/TableTreeBuilderTests.cpp
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "PrintTo_Qt.h"
|
||||||
|
|
||||||
|
#include "catalog/PgClass.h"
|
||||||
|
#include "catalog/PgDatabaseCatalog.h"
|
||||||
|
#include "ui/catalog/tables/TableTreeBuilder.h"
|
||||||
|
#include "ui/catalog/tables/TableNode.h"
|
||||||
|
#include "catalog/PgInheritsContainer.h"
|
||||||
|
|
||||||
|
TEST(TableTreeBuilder, EmptySourceEmptyResult)
|
||||||
|
{
|
||||||
|
std::map<Oid, PgClass> source;
|
||||||
|
PgDatabaseCatalog catalog;
|
||||||
|
PgInheritsContainer inherited(catalog);
|
||||||
|
TableTreeBuilder builder(source, inherited);
|
||||||
|
auto [result, index] = builder.Build();
|
||||||
|
|
||||||
|
EXPECT_EQ(result->children.size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(TableTreeBuilder, TopLevelOnly)
|
||||||
|
{
|
||||||
|
std::map<Oid, PgClass> source;
|
||||||
|
|
||||||
|
PgDatabaseCatalog catalog;
|
||||||
|
PgClass cls1(catalog, 1000, "a", 11);
|
||||||
|
source.emplace(1000, cls1);
|
||||||
|
PgInheritsContainer inherited(catalog);
|
||||||
|
TableTreeBuilder builder(source, inherited);
|
||||||
|
auto [result, index] = builder.Build();
|
||||||
|
|
||||||
|
EXPECT_EQ(result->children.size(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeIFindParents : public IFindParents
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<Oid> getParentsOf(Oid oid) const override
|
||||||
|
{
|
||||||
|
if (oid == 1001)
|
||||||
|
return { 1002 };
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(TableTreeBuilder, WithChild)
|
||||||
|
{
|
||||||
|
std::map<Oid, PgClass> source;
|
||||||
|
|
||||||
|
FakeIFindParents findParents;
|
||||||
|
PgDatabaseCatalog catalog;
|
||||||
|
PgClass cls1(catalog, 1001, "a", 11);
|
||||||
|
source.emplace(1001, cls1);
|
||||||
|
PgClass cls2(catalog, 1002, "b", 11);
|
||||||
|
source.emplace(1002, cls2);
|
||||||
|
PgInheritsContainer inherited(catalog);
|
||||||
|
TableTreeBuilder builder(source, findParents);
|
||||||
|
auto [result, index] = builder.Build();
|
||||||
|
|
||||||
|
EXPECT_EQ(result->children.size(), 1);
|
||||||
|
EXPECT_EQ(result->children[0]->children.size(), 1);
|
||||||
|
EXPECT_TRUE(result->children[0]->children[0]->parent.lock() == result->children[0]);
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,7 @@ QT += core widgets
|
||||||
HEADERS +=
|
HEADERS +=
|
||||||
|
|
||||||
SOURCES += main.cpp \
|
SOURCES += main.cpp \
|
||||||
|
TableTreeBuilderTests.cpp \
|
||||||
tst_ConvertLangToSqlString.cpp \
|
tst_ConvertLangToSqlString.cpp \
|
||||||
tst_ConvertToMultiLineCString.cpp \
|
tst_ConvertToMultiLineCString.cpp \
|
||||||
tst_ExplainJsonParser.cpp \
|
tst_ExplainJsonParser.cpp \
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue