Reorganization of pgLab project

This commit is contained in:
eelke 2022-04-09 07:10:29 +02:00
parent 7300865c77
commit c71fdc4af7
78 changed files with 204 additions and 148 deletions

View file

@ -0,0 +1,58 @@
#include "catalog/delegates/IconColumnDelegate.h"
#include <QPainter>
IconColumnDelegate::IconColumnDelegate(QWidget *parent)
: QStyledItemDelegate(parent)
{
}
IconColumnDelegate::~IconColumnDelegate()
{
clearCache();
}
void IconColumnDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.data().canConvert<QString>()) {
auto icon_name = qvariant_cast<QString>(index.data());
QIcon* icon = IconColumnDelegate::getIcon(icon_name);
if (icon) {
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.highlight());
icon->paint(painter, option.rect);
}
else
QStyledItemDelegate::paint(painter, option, index);
} else {
QStyledItemDelegate::paint(painter, option, index);
}
}
QSize IconColumnDelegate::sizeHint(const QStyleOptionViewItem &,
const QModelIndex &) const
{
return QSize(16, 16);
}
void IconColumnDelegate::clearCache()
{
for (auto &e : m_Icons)
delete e.second;
m_Icons.clear();
}
QIcon* IconColumnDelegate::getIcon(const QString &name) const
{
auto fr = m_Icons.find(name);
if (fr == m_Icons.end()) {
// load and insert icon
auto icon = new QIcon(name);
fr = m_Icons.emplace(name, icon).first;
}
return fr->second;
}

View file

@ -0,0 +1,29 @@
#ifndef ICONCOLUMNDELEGATE_H
#define ICONCOLUMNDELEGATE_H
#include <QStyledItemDelegate>
#include <map>
/** This class asumes that the string values supplies for the column data
* can be Resolved by QIcon to an actual icon. Icons are cached and reused.
*
*/
class IconColumnDelegate: public QStyledItemDelegate {
public:
IconColumnDelegate(QWidget *parent = nullptr);
~IconColumnDelegate() override;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
void clearCache();
private:
using t_IconCache = std::map<QString, QIcon*>;
mutable t_IconCache m_Icons;
QIcon* getIcon(const QString &name) const;
};
#endif // ICONCOLUMNDELEGATE_H

View file

@ -0,0 +1,28 @@
#include "BaseTableModel.h"
#include "CustomDataRole.h"
#include "ResultTableModelUtil.h"
#include <QBrush>
#include "Pgsql_oids.h"
using namespace Pgsql;
QVariant BaseTableModel::data(const QModelIndex &index, int role) const
{
QVariant v;
Oid oid = getType(index.column());
if (role == Qt::DisplayRole) {
v = getData(index);
}
else if (role == CustomDataTypeRole) {
v = oid;
}
else if (role == CustomDataMeaningRole) {
v = getDataMeaning(index);
}
return v;
}
QVariant BaseTableModel::getDataMeaning(const QModelIndex &) const
{
return static_cast<int>(DataMeaningNormal);
}

View file

@ -0,0 +1,23 @@
#ifndef BASETABLEMODEL_H
#define BASETABLEMODEL_H
#include <QAbstractTableModel>
#include "Pgsql_declare.h"
class BaseTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
using QAbstractTableModel::QAbstractTableModel;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
protected:
virtual Oid getType(int column) const = 0;
virtual QVariant getData(const QModelIndex &index) const = 0;
virtual QVariant getDataMeaning(const QModelIndex &index) const;
};
#endif // BASETABLEMODEL_H

View file

@ -0,0 +1,318 @@
#include "catalog/models/ColumnTableModel.h"
#include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgAttribute.h"
#include "catalog/PgAttributeContainer.h"
#include "catalog/PgClassContainer.h"
#include "catalog/PgConstraintContainer.h"
#include "catalog/PgCollation.h"
#include "catalog/PgCollationContainer.h"
#include "catalog/PgType.h"
#include "catalog/PgTypeContainer.h"
#include "catalog/PgIndexContainer.h"
#include "ScopeGuard.h"
#include "SqlFormattingUtils.h"
#include <QBrush>
namespace {
// Filter dropped and system columns but keep the oid column
bool ColumnFilterWithOidsPred(PgAttribute &e)
{
return e.isdropped || (e.num <= 0 && e.name != "oid");
}
// Filter dropped and system columns
bool ColumnFilterWithoutOidsPred(PgAttribute &e)
{
return e.isdropped || e.num <= 0;
}
}
void ColumnTableModel::setData(std::shared_ptr<const PgDatabaseCatalog> cat, const std::optional<PgClass> &table)
{
if (cat != m_catalog) {
m_catalog = cat;
refreshConnection = connect(m_catalog.get(), &PgDatabaseCatalog::refreshed, this, &ColumnTableModel::refresh);
}
m_table = table;
refresh();
}
QVariant ColumnTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
QVariant v;
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
QString c;
if (section >= colCount) {
const auto &tbl_idx = m_indexes[section - colCount];
if (tbl_idx.isprimary)
c = "PK";
else if (tbl_idx.isunique)
c = "UIdx";
else
c = "Idx";
}
else {
switch (section) {
case AttnumCol:
c = tr("#");
break;
case NameCol:
c = tr("Name");
break;
case TypeCol:
c = tr("Type");
break;
case NullCol:
c = tr("N");
break;
case DefaultCol:
c = tr("Default");
break;
case ForeignKeyCol:
c = tr("Refs");
break;
case CollationCol:
c = tr("Collation");
break;
case CommentCol:
c = tr("Comment");
break;
}
}
v = c;
}
else if (role == Qt::ToolTipRole) {
if (section >= colCount) {
const auto &tbl_idx = m_indexes[section - colCount];
//auto idx_cls = m_catalog->classes()->getByKey(tbl_idx.indexrelid);
auto idx_class_name = tbl_idx.objectName(); // getClassDisplayString(*m_catalog, tbl_idx.indexrelid);
QString s;
if (tbl_idx.isprimary)
s = tr("Primary key");
else if (tbl_idx.isunique)
s = tr("Unique index");
else
s = tr("Index");
s += "\n" + idx_class_name;
v = s;
}
else {
switch (section) {
// case NameCol:
// c = tr("Name");
// break;
// case TypeCol:
// c = tr("Type");
// break;
case NullCol:
v = tr("N = Column is nullable");
break;
case DefaultCol:
v = tr("Default value for the columns");
break;
case ForeignKeyCol:
v = tr("Foreign key constraint for this column");
break;
// case CollationCol:
// c = tr("Collation");
// break;
}
}
}
}
return v;
}
int ColumnTableModel::rowCount(const QModelIndex &/*parent*/) const
{
return static_cast<int>(m_columns.size());
}
int ColumnTableModel::columnCount(const QModelIndex &/*parent*/) const
{
return colCount + m_indexes.size();
}
Oid ColumnTableModel::getType(int /*column*/) const
{
Oid oid = Pgsql::varchar_oid;
// switch (column) {
// case TypeCol:
// case NameCol:
// case NullCol:
// case DefaultCol:
// case CollationCol:
// oid = VARCHAROID;
// break;
// c = tr("Collation");
// break;
// }
return oid;
}
QVariant ColumnTableModel::getData(const QModelIndex &index) const
{
QVariant v;
const int row = index.row();
const auto &t = m_columns[row];
const int col = index.column();
if (col >= colCount) {
const auto &tbl_idx = m_indexes[col - colCount];
int i = 1;
for (auto attr : tbl_idx.key) {
if (attr == t.num) {
v = i;
break;
}
++i;
}
}
else {
switch (col) {
case AttnumCol:
//s = QString::asprintf("%d", (int) t.num);
//break;
return static_cast<int>(t.num);
case NameCol:
v = t.name;
break;
case TypeCol:
v = getTypeDisplayString(*m_catalog, t.typid, t.typmod);
break;
case NullCol:
v = QString::fromStdU16String(t.notnull ? u"" : u"N");
break;
case DefaultCol:
v = t.defaultValue;
break;
case ForeignKeyCol:
v = getFKey(t);
break;
case CollationCol:
if (t.collation != InvalidOid) {
auto&& col = m_catalog->collations()->getByKey(t.collation);
if (col)
v = col->objectName();
}
break;
case CommentCol:
v = t.description;
break;
}
}
return v;
}
QString ColumnTableModel::getFKey(const PgAttribute &column) const
{
QString result;
auto&& list = m_catalog->constraints()->getFKeyForTableColumn(column.relid, column.num);
for (auto&& elem : list) {
if (elem.key[0] == column.num) {
//result = elem.name;
result = getForeignKeyConstraintReferencesShort(*m_catalog, elem);
}
}
return result;
}
void ColumnTableModel::refresh()
{
beginResetModel();
SCOPE_EXIT { endResetModel(); };
if (m_table) {
m_columns = m_catalog->attributes()->getColumnsForRelation(m_table->oid());
// hide system and dropped columns
auto column_filter_pred = m_table->hasoids ? ColumnFilterWithOidsPred : ColumnFilterWithoutOidsPred;
auto si = std::remove_if(m_columns.begin(), m_columns.end(), column_filter_pred);
// move columns to end and remove them
m_columns.erase(si, m_columns.end());
// sort remaining columns by order in table
std::sort(m_columns.begin(), m_columns.end(),
[] (auto &l, auto &r) -> bool { return l.num < r.num; });
}
else
m_columns.clear();
if (m_table) {
m_indexes = m_catalog->indexes()->getIndexesForTable(m_table->oid());
std::sort(m_indexes.begin(), m_indexes.end(),
[] (const auto &l, const auto &r) -> bool
{
return l.isprimary > r.isprimary
|| (l.isprimary == r.isprimary && l.oid() < r.oid());
});
}
else
m_indexes.clear();
emit
}
QVariant ColumnTableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::ForegroundRole && index.column() == TypeCol) {
QVariant v;
const auto &t = m_columns[index.row()];
if (t.typid == InvalidOid)
v = QBrush(Qt::black);
else {
auto c = m_catalog->types()->getByKey(t.typid);
switch (c->category) {
case TypCategory::Boolean:
v = QBrush(Qt::darkGreen);
break;
case TypCategory::Numeric:
v = QBrush(Qt::darkBlue);
break;
case TypCategory::DateTime:
case TypCategory::Timespan:
v = QBrush(Qt::darkMagenta);
break;
case TypCategory::String:
v = QBrush(Qt::darkYellow);
break;
case TypCategory::Array:
case TypCategory::Composite:
case TypCategory::Enum:
case TypCategory::Geometric:
case TypCategory::NetworkAddress:
case TypCategory::Pseudo:
case TypCategory::Range:
case TypCategory::UserDefined:
case TypCategory::BitString:
case TypCategory::Unknown:
default:
v = QBrush(Qt::black);
}
}
return v;
}
if (role == Qt::TextAlignmentRole) {
QVariant v;
int col = index.column();
if (col == NullCol || col >= colCount)
v = int(Qt::AlignCenter | Qt::AlignVCenter);
else
v = int(Qt::AlignLeft | Qt::AlignVCenter);
return v;
}
return BaseTableModel::data(index, role);
}
const PgAttribute& ColumnTableModel::column(int row) const
{
return m_columns.at(static_cast<size_t>(row));
}

View file

@ -0,0 +1,66 @@
#ifndef COLUMNTABLEMODEL_H
#define COLUMNTABLEMODEL_H
#include "catalog/models/BaseTableModel.h"
#include "catalog/PgAttribute.h"
#include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgClass.h"
#include "catalog/PgIndex.h"
#include <memory>
#include <optional>
#include <vector>
class PgDatabaseCatalog;
class PgAttribute;
class ColumnTableModel: public BaseTableModel {
Q_OBJECT
public:
enum e_Columns : int {
AttnumCol,
NameCol, ///
TypeCol,
NullCol,
DefaultCol,
ForeignKeyCol,
CollationCol,
CommentCol,
colCount };
using BaseTableModel::BaseTableModel;
void setData(std::shared_ptr<const PgDatabaseCatalog> cat, const std::optional<PgClass> &table);
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
// Basic functionality:
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
const PgAttribute& column(int row) const;
protected:
virtual Oid getType(int column) const override;
virtual QVariant getData(const QModelIndex &index) const override;
using t_Columns = std::vector<PgAttribute>;
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
std::optional<PgClass> m_table;
t_Columns m_columns;
std::vector<PgIndex> m_indexes;
QMetaObject::Connection refreshConnection;
QString getFKey(const PgAttribute &column) const;
private slots:
/// Retrieves required data from catalog, called everytime it might have changed
void refresh();
};
#endif // COLUMNTABLEMODEL_H

View file

@ -0,0 +1,157 @@
#include "ConstraintModel.h"
#include "ScopeGuard.h"
#include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgConstraintContainer.h"
#include "Pgsql_oids.h"
ConstraintModel::ConstraintModel(QObject *parent)
: BaseTableModel(parent)
{
}
void ConstraintModel::setData(std::shared_ptr<const PgDatabaseCatalog> cat, const std::optional<PgClass> &table)
{
if (cat != m_catalog) {
m_catalog = cat;
refreshConnection = connect(m_catalog.get(), &PgDatabaseCatalog::refreshed, this, &ConstraintModel::refresh);
}
m_table = table;
refresh();
}
void ConstraintModel::refresh()
{
beginResetModel();
SCOPE_EXIT { endResetModel(); };
if (m_table) {
m_constraints = m_catalog->constraints()->getConstraintsForRelation(m_table->oid());
std::sort(m_constraints.begin(), m_constraints.end(),
[] (auto &l, auto &r) {
return l.type < r.type ||
(l.type == r.type && l.objectName() < r.objectName());
});
}
else
m_constraints.clear();
}
QVariant ConstraintModel::headerData(int section, Qt::Orientation orientation, int role) const
{
QVariant v;
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
QString c;
switch (section) {
case TypeCol:
c = tr("Type");
break;
case NameCol:
c = tr("Name");
break;
case NsCol:
c = tr("Schema");
break;
case SupportingIndexCol:
c = tr("Supporting index");
break;
// case DefinitionCol:
// c = tr("Definition");
// break;
}
v = c;
}
}
return v;
}
int ConstraintModel::rowCount(const QModelIndex &) const
{
return static_cast<int>(m_constraints.size());
}
int ConstraintModel::columnCount(const QModelIndex &) const
{
return colCount;
}
//QVariant ConstraintModel::data(const QModelIndex &index, int role) const
//{
// QVariant v;
// if (!index.isValid())
// return QVariant();
// // FIXME: Implement me!
// return v;
//}
Oid ConstraintModel::getType(int ) const
{
Oid oid = Pgsql::varchar_oid;
return oid;
}
QString IconForConstraintType(ConstraintType ct)
{
QString s = ":/icons/constraints/";
switch (ct) {
case ConstraintType::Check:
s += "check.png";
break;
case ConstraintType::ForeignKey:
s += "foreignkey.png";
break;
case ConstraintType::PrimaryKey:
s += "primarykey.png";
break;
case ConstraintType::Unique:
s += "unique.png";
break;
case ConstraintType::ConstraintTrigger:
s = "CT";
break;
case ConstraintType::ExclusionConstraint:
s = "XC";
break;
default:
s = "?";
break;
}
return s;
}
QVariant ConstraintModel::getData(const QModelIndex &index) const
{
QVariant v;
const int row = index.row();
const auto &t = m_constraints[row];
const int col = index.column();
QString s;
switch (col) {
case TypeCol:
s = IconForConstraintType(t.type);
break;
case NameCol:
s = t.objectName();
break;
case NsCol:
s = t.nsName();
break;
case SupportingIndexCol:
s = getIndexDisplayString(*m_catalog, t.indid);
break;
// case DefinitionCol:
// s = t.definition;
// break;
}
v = s;
return v;
}
const PgConstraint& ConstraintModel::constraint(int row)
{
return m_constraints[row];
}

View file

@ -0,0 +1,57 @@
#ifndef CONSTRAINTMODEL_H
#define CONSTRAINTMODEL_H
#include "BaseTableModel.h"
#include "catalog/PgClass.h"
#include "catalog/PgConstraint.h"
#include <QAbstractTableModel>
#include <optional>
#include <vector>
class PgDatabaseCatalog;
class ConstraintModel : public BaseTableModel {
Q_OBJECT
public:
enum e_Columns : int {
TypeCol,
NameCol, ///
NsCol, ///
SupportingIndexCol,
// DefinitionCol,
colCount };
explicit ConstraintModel(QObject *parent = nullptr);
void setData(std::shared_ptr<const PgDatabaseCatalog> cat, const std::optional<PgClass> &table);
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
//QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
const PgConstraint& constraint(int row);
protected:
virtual Oid getType(int column) const override;
virtual QVariant getData(const QModelIndex &index) const override;
private:
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
std::optional<PgClass> m_table;
using t_Constraints = std::vector<PgConstraint>;
t_Constraints m_constraints;
QMetaObject::Connection refreshConnection;
private slots:
void refresh();
};
#endif // CONSTRAINTMODEL_H

View file

@ -0,0 +1,245 @@
#include "DatabasesTableModel.h"
#include "CustomDataRole.h"
#include "OpenDatabase.h"
#include "ScopeGuard.h"
#include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgDatabaseContainer.h"
#include "catalog/PgAuthIdContainer.h"
#include "ResultTableModelUtil.h"
#include <QtConcurrent>
#include "Pgsql_Connection.h"
using namespace Pgsql;
DatabasesTableModel::DatabasesTableModel(std::shared_ptr<OpenDatabase> opendatabase, QObject *parent)
: BaseTableModel(parent)
, openDatabase(opendatabase)
{
}
void DatabasesTableModel::setDatabaseList(std::shared_ptr<const PgDatabaseCatalog> cat)
{
beginResetModel();
SCOPE_EXIT { endResetModel(); };
databases.clear();
std::map<Oid, int> oidIndex;
m_catalog = cat;
auto dats = cat->databases();
databases.reserve(dats->count());
for (const auto& d : *dats)
{
databases.emplace_back(d);
oidIndex.emplace(d.oid(), databases.size() - 1);
}
StartLoadDatabaseSizes(std::move(oidIndex));
}
QVariant DatabasesTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
QVariant v;
if (orientation == Qt::Horizontal)
{
if (role == Qt::DisplayRole)
{
switch (section) {
case NameCol:
v = tr("Name");
break;
case DbaCol:
v = tr("Owner");
break;
case EncodingCol:
v = tr("Encoding");
break;
case CollateCol:
v = tr("Collation");
break;
case CTypeCol:
v = tr("CType");
break;
case IsTemplateCol:
v = tr("Is template");
break;
case AllowConnCol:
v = tr("Can connect");
break;
case ConnLimitCol:
v = tr("Conn. limit");
break;
case TablespaceCol:
v = tr("Tablespace");
break;
case CommentCol:
v = tr("Comment");
break;
case SizeCol:
v = tr("Size");
break;
case AclCol:
v = tr("ACL");
break;
}
}
}
return v;
}
int DatabasesTableModel::rowCount(const QModelIndex &) const
{
int result = 0;
result = databases.size();
return result;
}
int DatabasesTableModel::columnCount(const QModelIndex &) const
{
int result = COL_COUNT;
return result;
}
Oid DatabasesTableModel::getType(int column) const
{
Oid oid;
switch (column)
{
case AllowConnCol:
case IsTemplateCol:
oid = Pgsql::bool_oid;
break;
case ConnLimitCol:
oid = Pgsql::int4_oid;
break;
case SizeCol:
oid = Pgsql::int8_oid;
break;
case AclCol:
case CollateCol:
case CTypeCol:
case EncodingCol:
case DbaCol:
case NameCol:
case TablespaceCol:
case CommentCol:
oid = Pgsql::varchar_oid;
break;
default:
oid = InvalidOid;
}
return oid;
}
QVariant DatabasesTableModel::getData(const QModelIndex &index) const
{
QVariant v;
const Database &d = databases[index.row()];
const PgDatabase &db = d.database;
switch (index.column()) {
case NameCol:
v = db.objectName();
break;
case DbaCol:
v = db.ownerName();
break;
case EncodingCol:
v = db.encodingString;
break;
case CollateCol:
v = db.collate;
break;
case CTypeCol:
v = db.ctype;
break;
case IsTemplateCol:
v = db.isTemplate;
break;
case AllowConnCol:
v = db.allowConn;
break;
case ConnLimitCol:
v = db.connLimit;
break;
case TablespaceCol:
v = getTablespaceDisplayString(*m_catalog, db.tablespace);
break;
case CommentCol:
v = db.description;
break;
case SizeCol:
if (d.size.totalBytes >= 0)
v = d.size.totalBytes;
break;
case AclCol:
v = db.aclString();
break;
}
return v;
}
QVariant DatabasesTableModel::getDataMeaning(const QModelIndex &index) const
{
if (index.column() == SizeCol)
{
return static_cast<int>(DataMeaningBytes);
}
return BaseTableModel::getDataMeaning(index);
}
void DatabasesTableModel::StartLoadDatabaseSizes(std::map<Oid, int> oidIndex)
{
QPointer p(this);
QtConcurrent::run([this]
{
return QueryDatabaseSizes();
})
.then(qApp, [p, oi = std::move(oidIndex)] (DatabaseSizes sizes)
{
if (p)
{
p.data()->PopulateSizes(std::move(oi), std::move(sizes));
}
});
}
DatabasesTableModel::DatabaseSizes DatabasesTableModel::QueryDatabaseSizes()
{
std::string q =
"SELECT pg_database.oid, "
" case when has_database_privilege(current_role, pg_database.oid, \n"
" 'connect') then pg_database_size(pg_database.oid) else -1 end \n"
"FROM pg_database";
Pgsql::Connection connection;
connection.connect(openDatabase->config().connectionString());
Pgsql::Result sizesResult = connection.query(q.c_str());
DatabaseSizes result;
result.reserve(sizesResult.rows());
for (auto& row : sizesResult)
{
DatabaseSize ds;
ds.oid = row.get(0);
ds.totalBytes = row.get(1);
result.push_back(ds);
}
return result;
}
void DatabasesTableModel::PopulateSizes(std::map<Oid, int> oidIndex, DatabaseSizes sizes)
{
for (auto & s : sizes)
{
auto findIter = oidIndex.find(s.oid);
if (findIter != oidIndex.end())
{
databases[findIter->second].size = s;
}
}
emit dataChanged(
createIndex(0, SizeCol),
createIndex(static_cast<int>(databases.size()), SizeCol)
);
}

View file

@ -0,0 +1,80 @@
#ifndef DATABASESTABLEMODEL_H
#define DATABASESTABLEMODEL_H
#include "BaseTableModel.h"
#include "catalog/PgDatabase.h"
#include <memory>
class OpenDatabase;
class PgDatabaseCatalog;
/** Class for displaying the list of databases of a server in a QTableView
*
*/
class DatabasesTableModel : public BaseTableModel
{
Q_OBJECT
public:
using RowItem = PgDatabase;
enum e_Columns : int { NameCol, DbaCol, EncodingCol, CollateCol,
CTypeCol, IsTemplateCol, AllowConnCol, ConnLimitCol,
TablespaceCol, CommentCol, SizeCol, AclCol, COL_COUNT };
explicit DatabasesTableModel(std::shared_ptr<OpenDatabase> opendatabase, QObject *parent);
void setDatabaseList(std::shared_ptr<const PgDatabaseCatalog> cat);
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
virtual Oid getType(int column) const override;
virtual QVariant getData(const QModelIndex &index) const override;
RowItem rowItem(int row) const
{
return databases.at(row).database;
}
protected:
virtual QVariant getDataMeaning(const QModelIndex &index) const override;
private:
class DatabaseSize {
public:
Oid oid;
int64_t totalBytes;
DatabaseSize()
: oid(InvalidOid)
, totalBytes(-1)
{}
};
using DatabaseSizes = std::vector<DatabaseSize>;
class Database {
public:
PgDatabase database;
DatabaseSize size;
Database(const PgDatabase &db)
: database(db)
{}
};
using Databases = std::vector<Database>;
std::shared_ptr<OpenDatabase> openDatabase;
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
Databases databases;
void StartLoadDatabaseSizes(std::map<Oid, int> oidIndex);
DatabaseSizes QueryDatabaseSizes();
void PopulateSizes(std::map<Oid, int> oidIndex, DatabaseSizes sizes);
};
#endif // DATABASESTABLEMODEL_H

View file

@ -0,0 +1,94 @@
#include "DependantsTableModel.h"
#include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgConstraintContainer.h"
#include "catalog/PgClassContainer.h"
DependantsTableModel::DependantsTableModel(QObject *parent)
: QAbstractTableModel(parent)
{
}
void DependantsTableModel::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
{
if (cat != m_catalog) {
m_catalog = cat;
refreshConnection = connect(m_catalog.get(), &PgDatabaseCatalog::refreshed,
this, &DependantsTableModel::refresh);
}
refresh();
}
void DependantsTableModel::loadForTable(Oid table_id)
{
if (table_id != tableId) {
tableId = table_id;
refresh();
}
}
QVariant DependantsTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
switch (section) {
case NameCol: return tr("Table");
case NamespaceCol: return tr("Namespace");
}
}
}
return {};
}
int DependantsTableModel::rowCount(const QModelIndex &) const
{
return dependants.size();
}
int DependantsTableModel::columnCount(const QModelIndex &) const
{
return colCount;
}
QVariant DependantsTableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole) {
auto&& data = dependants[index.row()];
switch (index.column()) {
case NameCol: return data.tableName;
case NamespaceCol: return data.namespaceName;
case ConstraintCol: return data.constraintName;
}
}
return {};
}
void DependantsTableModel::refresh()
{
if (!m_catalog)
return;
beginResetModel();
dependants.clear();
if (tableId != InvalidOid) {
auto&& constraints = m_catalog->constraints();
auto fkeys = constraints->getReferencedForRelation(tableId);
dependants.reserve(static_cast<int>(fkeys.size()));
auto&& tables = m_catalog->classes();
for (auto&& fk : fkeys) {
//dependants.append(
auto t = tables->getByKey(fk.relid);
if (t) {
Item i;
i.tableOid = t->oid();
i.tableName = t->objectName();
i.namespaceName = t->nsName();
i.constraintName = fk.objectName();
dependants.push_back(i);
}
}
}
endResetModel();
}

View file

@ -0,0 +1,55 @@
#ifndef DEPENDENTSTABLEMODEL_H
#define DEPENDENTSTABLEMODEL_H
#include <QAbstractTableModel>
#include <memory>
#include "catalog/PgClass.h"
#include "Pgsql_oids.h"
#include <QVector>
class PgDatabaseCatalog;
class DependantsTableModel: public QAbstractTableModel {
Q_OBJECT
public:
enum e_Columns : int {
NameCol, //
NamespaceCol, // Schema
ConstraintCol,
colCount
};
DependantsTableModel(QObject *parent = nullptr);
void setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat);
void loadForTable(Oid table_id);
// Basic functionality:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
private:
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
QMetaObject::Connection refreshConnection;
Oid tableId;
class Item {
public:
Oid tableOid;
QString tableName;
QString namespaceName;
QString constraintName;
};
QVector<Item> dependants;
private slots:
void refresh();
};
#endif // DEPENDENTSTABLEMODEL_H

View file

@ -0,0 +1,142 @@
#include "IndexModel.h"
#include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgIndexContainer.h"
#include "Pgsql_oids.h"
#include "ScopeGuard.h"
#include "CustomDataRole.h"
void IndexModel::setData(std::shared_ptr<const PgDatabaseCatalog> cat, const std::optional<PgClass> &table)
{
if (cat != m_catalog) {
m_catalog = cat;
refreshConnection = connect(m_catalog.get(), &PgDatabaseCatalog::refreshed, this, &IndexModel::refresh);
}
m_table = table;
refresh();
}
void IndexModel::refresh()
{
beginResetModel();
SCOPE_EXIT { endResetModel(); };
if (m_table)
m_indexes = m_catalog->indexes()->getIndexesForTable(m_table->oid());
else
m_indexes.clear();
}
int IndexModel::rowCount(const QModelIndex &/*parent*/) const
{
return (int)m_indexes.size();
}
int IndexModel::columnCount(const QModelIndex &/*parent*/) const
{
return colCount;
}
Oid IndexModel::getType(int column) const
{
switch (column) {
case SizeCol:
return Pgsql::int8_oid;
case ExplicitIndexCol:
return Pgsql::bool_oid;
default:
return Pgsql::varchar_oid;
}
}
QVariant IndexModel::headerData(int section, Qt::Orientation orientation, int role) const
{
QVariant v;
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
QString c;
switch (section) {
case TypeCol:
c = tr("Type");
break;
case NameCol:
c = tr("Name");
break;
case AmCol:
c = tr("AM");
break;
case ColumnsCol:
c = tr("On");
break;
case ConditionCol:
c = tr("Condition");
break;
case SizeCol:
c = tr("Size");
break;
case ExplicitIndexCol:
c = tr("Explicit");
break;
// case DefinitionCol:
// c = tr("Definition");
// break;
}
v = c;
}
}
return v;
}
QVariant IndexModel::getData(const QModelIndex &index) const
{
QVariant v;
int rij = index.row();
const auto &dat = m_indexes[rij];
switch (index.column()) {
case TypeCol:
if (dat.isprimary) v = ":/icons/constraints/primarykey.png";
else if (dat.isunique) v = ":/icons/constraints/unique.png";
else v = ":/icons/constraints/index.png";
break;
case NameCol:
v = dat.objectName(); // getIndexDisplayString(*m_catalog, dat.indexrelid);
break;
case AmCol:
v = dat.getAm();
break;
case ColumnsCol:
break;
case ConditionCol:
break;
case SizeCol:
v = dat.sizeBytes;
break;
case ExplicitIndexCol:
v = !dat.isSupportingIndex();
break;
}
return v;
}
QVariant IndexModel::data(const QModelIndex &index, int role) const
{
QVariant v;
if (role == Qt::DisplayRole)
v = getData(index);
else if (role == CustomDataTypeRole)
v = getType(index.column());
else if (role == CustomDataMeaningRole) {
switch (index.column()) {
case SizeCol:
return static_cast<int>(DataMeaningBytes);
default:
return static_cast<int>(DataMeaningNormal);
}
}
return v;
}

View file

@ -0,0 +1,68 @@
#ifndef INDEXMODEL_H
#define INDEXMODEL_H
#include <QAbstractTableModel>
#include "catalog/PgClass.h"
#include "catalog/PgIndex.h"
#include <memory>
#include <optional>
#include <vector>
class PgDatabaseCatalog;
class IndexModel: public QAbstractTableModel {
Q_OBJECT
public:
using QAbstractTableModel::QAbstractTableModel;
enum e_Columns : int {
TypeCol, /// primary/unique/normal
NameCol, ///
AmCol, ///< Access Method
ColumnsCol, ///
ConditionCol,
SizeCol,
ExplicitIndexCol,
colCount };
// oid
// tablespace
// operator class
// unique
// primary
// clustered
// valid
// constraint
// system index
// fill factor
// comment
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
void setData(std::shared_ptr<const PgDatabaseCatalog> cat, const std::optional<PgClass> &table);
// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex &index, int role) const override;
PgIndex getIndex(int row) const { return m_indexes[row]; }
protected:
Oid getType(int column) const;
QVariant getData(const QModelIndex &index) const;
private:
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
std::optional<PgClass> m_table;
using t_Indexes = std::vector<PgIndex>;
t_Indexes m_indexes;
QMetaObject::Connection refreshConnection;
private slots:
void refresh();
};
#endif // INDEXMODEL_H

View file

@ -0,0 +1,131 @@
#include "ProcTableModel.h"
#include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgProcContainer.h"
#include "catalog/PgLanguageContainer.h"
#include "catalog/PgNamespace.h"
#include "CustomDataRole.h"
ProcTableModel::ProcTableModel(QObject *parent)
: QAbstractTableModel(parent)
{
}
QVariant ProcTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
switch (section) {
case NameCol: return tr("Name");
case NamespaceCol: return tr("Schema");
case OwnerCol: return tr("Owner");
case LangCol: return tr("Language");
case AclCol: return tr("ACL");
}
}
}
return QVariant();
}
void ProcTableModel::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
{
if (cat != m_catalog) {
m_catalog = cat;
refreshConnection = connect(m_catalog.get(), &PgDatabaseCatalog::refreshed,
this, &ProcTableModel::refresh);
}
refresh();
}
void ProcTableModel::setNamespaceFilter(NamespaceFilter filter)
{
m_namespaceFilter = filter;
refresh();
}
void ProcTableModel::refresh()
{
if (!m_catalog)
return;
beginResetModel();
auto && procs = m_catalog->procs();
m_procs.clear();
for (auto&& p : *procs) {
bool add = false;
switch (m_namespaceFilter) {
case NamespaceFilter::User:
add = !p.ns().isSystemCatalog();
break;
case NamespaceFilter::PgCatalog:
add = p.ns().objectName() == "pg_catalog";
break;
case NamespaceFilter::InformationSchema:
add = p.ns().objectName() == "information_schema";
break;
}
if (add)
m_procs.push_back(p);
}
endResetModel();
}
int ProcTableModel::rowCount(const QModelIndex &) const
{
return static_cast<int>(m_procs.size());
}
int ProcTableModel::columnCount(const QModelIndex &) const
{
return colCount;
}
QVariant ProcTableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
return getData(index);
else if (role == CustomDataTypeRole)
return getType(index.column());
// else if (role == FirstHiddenValue) {
// auto&& t = m_triggers->getByIdx(index.row());
// return t.relid; //
// }
return QVariant();
}
PgProc ProcTableModel::proc(int row) const
{
return m_procs.at(static_cast<size_t>(row));
}
Oid ProcTableModel::getType(int ) const
{
// switch (column) {
// case NameCol: return tr("Name");
// case NamespaceCol: return tr("Schema");
// case OwnerCol: return tr("Owner");
// case LangCol: return tr("Language");
// return Pgsql::bool_oid;
// }
return Pgsql::varchar_oid;
}
QVariant ProcTableModel::getData(const QModelIndex &index) const
{
auto&& t = m_procs.at(static_cast<size_t>(index.row()));
switch (index.column()) {
case NameCol: return t.objectName();
case NamespaceCol: return t.nsName();
case OwnerCol: return t.ownerName();
case LangCol: {
auto lan = m_catalog->languages()->getByKey(t.lang);
if (lan) return lan->objectName();
return t.lang;
}
case AclCol: return t.aclString();
}
return QVariant();
}

View file

@ -0,0 +1,60 @@
#ifndef PROCTABLEMODEL_H
#define PROCTABLEMODEL_H
#include "catalog/PgClass.h"
#include "catalog/PgProc.h"
#include "NamespaceFilter.h"
#include <QAbstractTableModel>
#include <memory>
class PgDatabaseCatalog;
class PgProcContainer;
/**
* @brief The ProcTableModel class
*
* Hidden values:
*
*/
class ProcTableModel: public QAbstractTableModel {
Q_OBJECT
public:
//using QAbstractTableModel::QAbstractTableModel;
enum e_Columns : int {
NameCol, //
NamespaceCol, // Schema
OwnerCol,
LangCol,
AclCol,
colCount
};
ProcTableModel(QObject *parent = nullptr);
void setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat);
void setNamespaceFilter(NamespaceFilter filter);
// Basic functionality:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
PgProc proc(int row) const;
private:
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
NamespaceFilter m_namespaceFilter = NamespaceFilter::User;
std::vector<PgProc> m_procs;
QMetaObject::Connection refreshConnection;
Oid getType(int column) const;
QVariant getData(const QModelIndex &index) const;
private slots:
void refresh();
};
#endif // PROCTABLEMODEL_H

View file

@ -0,0 +1,152 @@
#include "RolesTableModel.h"
#include "catalog/PgAuthIdContainer.h"
RolesTableModel::RolesTableModel(QObject *parent)
: BaseTableModel(parent)
{
}
void RolesTableModel::setRoleList(std::shared_ptr<const PgAuthIdContainer> roles)
{
beginResetModel();
m_roles = roles;
endResetModel();
}
QVariant RolesTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
QVariant v;
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
switch (section) {
case NameCol:
v = tr("Name");
break;
case SuperCol:
v = tr("Super");
break;
case InheritCol:
v = tr("Inherit");
break;
case CreateRoleCol:
v = tr("Create role");
break;
case CreateDBCol:
v = tr("Create DB");
break;
case CanLoginCol:
v = tr("Can login");
break;
case ReplicationCol:
v = tr("Replication");
break;
case BypassRlsCol:
v = tr("Bypass RLS");
break;
case ConnlimitCol:
v = tr("Connection limit");
break;
case ValidUntilCol:
v = tr("Valid until");
break;
}
}
}
return v;
}
int RolesTableModel::rowCount(const QModelIndex &/*parent*/) const
{
int result = 0;
if (m_roles) {
result = m_roles->count();
}
return result;
}
int RolesTableModel::columnCount(const QModelIndex &/*parent*/) const
{
int result = 10;
// if (parent.isValid())
// return 10;
return result;
}
Oid RolesTableModel::getType(int column) const
{
using namespace Pgsql;
Oid oid;
switch (column) {
case NameCol:
oid = varchar_oid;
break;
case ReplicationCol:
case BypassRlsCol:
case CanLoginCol:
case CreateDBCol:
case CreateRoleCol:
case InheritCol:
case SuperCol:
oid = bool_oid;
break;
case ConnlimitCol:
oid = int4_oid;
break;
case ValidUntilCol:
oid = timestamp_oid;
break;
default:
oid = InvalidOid;
}
return oid;
}
QVariant RolesTableModel::getData(const QModelIndex &index) const
{
QVariant v;
if (m_roles) {
const PgAuthId &authid = m_roles->getByIdx(index.row());
switch (index.column()) {
case NameCol:
v = authid.objectName();
break;
case SuperCol:
// todo lookup role name
v = authid.super;
break;
case InheritCol:
// todo lookup encoding name
v = authid.inherit;
break;
case CreateRoleCol:
v = authid.createRole;
break;
case CreateDBCol:
v = authid.createDB;
break;
case CanLoginCol:
v = authid.canlogin;
break;
case ReplicationCol:
v = authid.replication;
break;
case BypassRlsCol:
v = authid.bypassRls;
break;
case ConnlimitCol:
v = authid.connLimit;
break;
case ValidUntilCol:
v = authid.validUntil;
break;
}
}
return v;
}

View file

@ -0,0 +1,45 @@
#ifndef ROLESTABLEMODEL_H
#define ROLESTABLEMODEL_H
#include "BaseTableModel.h"
#include <memory>
class PgAuthId;
class PgAuthIdContainer;
/** Class for displaying the list of roles of a server in a QTableView
*
*/
class RolesTableModel : public BaseTableModel {
Q_OBJECT
public:
using RowItem = PgAuthId;
enum e_Columns : int { NameCol, SuperCol, InheritCol, CreateRoleCol,
CreateDBCol, CanLoginCol, ReplicationCol,
BypassRlsCol, ConnlimitCol, ValidUntilCol };
explicit RolesTableModel(QObject *parent);
void setRoleList(std::shared_ptr<const PgAuthIdContainer> roles);
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
virtual Oid getType(int column) const override;
virtual QVariant getData(const QModelIndex &index) const override;
// QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
private:
std::shared_ptr<const PgAuthIdContainer> m_roles;
};
#endif // ROLESTABLEMODEL_H

View file

@ -0,0 +1,118 @@
#include "SequenceModel.h"
#include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgNamespace.h"
#include "catalog/PgSequenceContainer.h"
SequenceModel::SequenceModel(QObject * parent)
: QAbstractTableModel(parent)
{}
QVariant SequenceModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
switch (section) {
case NameCol: return tr("Name");
case SchemaCol: return tr("Schema");
case OwnerCol: return tr("Owner");
case LastCol: return tr("Last");
case StartCol: return tr("Start");
case MinCol: return tr("Min");
case MaxCol: return tr("Max");
case IncrementCol: return tr("Inc");
case CacheCol: return tr("Cached");
case CycledCol: return tr("Cycled");
case CalledCol: return tr("Called");
case AclCol: return tr("ACL");
}
}
}
return {};
}
void SequenceModel::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
{
if (cat != m_catalog) {
m_catalog = cat;
refreshConnection = connect(m_catalog.get(), &PgDatabaseCatalog::refreshed,
this, &SequenceModel::refresh);
}
refresh();
}
void SequenceModel::setNamespaceFilter(NamespaceFilter filter)
{
m_namespaceFilter = filter;
refresh();
}
void SequenceModel::refresh()
{
if (!m_catalog)
return;
beginResetModel();
auto && seqs = m_catalog->sequences();
m_sequences.clear();
for (auto&& s : *seqs) {
bool add = false;
switch (m_namespaceFilter) {
case NamespaceFilter::User:
add = !s.ns().isSystemCatalog();
break;
case NamespaceFilter::PgCatalog:
add = s.ns().objectName() == "pg_catalog";
break;
case NamespaceFilter::InformationSchema:
add = s.ns().objectName() == "information_schema";
break;
}
if (add)
m_sequences.push_back(s);
}
endResetModel();
}
PgSequence SequenceModel::sequence(int row) const
{
return m_sequences.at(static_cast<size_t>(row));
}
int SequenceModel::rowCount(const QModelIndex &) const
{
return static_cast<int>(m_sequences.size());
}
int SequenceModel::columnCount(const QModelIndex &) const
{
return colCount;
}
QVariant SequenceModel::data(const QModelIndex &index, int role) const
{
if (m_sequences.empty())
return {};
int row = index.row();
auto && seq = m_sequences.at(static_cast<size_t>(row));
if (role == Qt::DisplayRole) {
switch (index.column()) {
case NameCol: return seq.objectName();
case SchemaCol: return seq.nsName();
case OwnerCol: return seq.ownerName();
case LastCol: return seq.last;
case StartCol: return seq.start;
case MinCol: return seq.min;
case MaxCol: return seq.max;
case IncrementCol: return seq.increment;
case CacheCol: return seq.cache;
case CycledCol: return seq.cycled;
case CalledCol: return seq.called;
case AclCol: return seq.aclString();
}
}
return {};
}

View file

@ -0,0 +1,53 @@
#ifndef SEQUENCEMODEL_H
#define SEQUENCEMODEL_H
#include "NamespaceFilter.h"
#include <QAbstractTableModel>
#include "catalog/PgSequence.h"
#include <memory>
class PgDatabaseCatalog;
class PgSequenceContainer;
class SequenceModel: public QAbstractTableModel {
Q_OBJECT
public:
enum e_Columns : int {
NameCol,
SchemaCol,
OwnerCol,
LastCol,
StartCol,
MinCol,
MaxCol,
IncrementCol,
CacheCol,
CycledCol,
CalledCol,
AclCol,
colCount
};
SequenceModel(QObject * parent = nullptr);
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
void setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat);
void setNamespaceFilter(NamespaceFilter filter);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
PgSequence sequence(int row) const;
private:
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
std::vector<PgSequence> m_sequences;
NamespaceFilter m_namespaceFilter = NamespaceFilter::User;
QMetaObject::Connection refreshConnection;
void refresh();
};
#endif // SEQUENCEMODEL_H

View file

@ -0,0 +1,259 @@
#include "TablesTableModel.h"
#include "OpenDatabase.h"
#include "ScopeGuard.h"
#include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgClass.h"
#include "catalog/PgClassContainer.h"
#include "catalog/PgNamespace.h"
#include "catalog/PgNamespaceContainer.h"
#include "Pgsql_declare.h"
#include "CustomDataRole.h"
#include <QBrush>
#include <QtConcurrent>
#include "Pgsql_Connection.h"
TablesTableModel::TablesTableModel(std::shared_ptr<OpenDatabase> opendatabase, QObject *parent)
: QAbstractTableModel(parent)
, openDatabase(opendatabase)
{}
void TablesTableModel::setNamespaceFilter(NamespaceFilter nsf)
{
m_namespaceFilter = nsf;
refresh();
}
void TablesTableModel::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
{
if (cat != m_catalog) {
m_catalog = cat;
refreshConnection = connect(m_catalog.get(), &PgDatabaseCatalog::refreshed,
this, &TablesTableModel::refresh);
}
refresh();
}
void TablesTableModel::refresh()
{
beginResetModel();
SCOPE_EXIT { endResetModel(); };
if (!m_catalog)
return;
// Later afscheiden naar filter functie
auto classes = m_catalog->classes();
std::map<Oid, int> oidIndex;
m_tables.clear();
for (const auto &e : *classes) {
bool add = false;
if (e.kind == RelKind::Table || e.kind == RelKind::View
|| e.kind == RelKind::MaterializedView || e.kind == RelKind::ForeignTable) {
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));
}
QVariant TablesTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
switch (section) {
case NameCol: return tr("Name");
case NamespaceCol: return tr("Schema");
case KindCol: return tr("Kind");
case OwnerCol: return tr("Owner");
case TablespaceCol: return tr("Tablespace");
case OptionsCol: return tr("Options");
case AclCol: return tr("ACL");
case CommentCol: return tr("Comment");
case TotalSizeCol: return tr("Total size");
case TableSizeCol: return tr("Table size");
case IndexSizeCol: return tr("Index size");
case ToastSizeCol: return tr("TOAST size");
}
}
}
return QVariant();
}
int TablesTableModel::rowCount(const QModelIndex &) const
{
return static_cast<int>(m_tables.size());
}
int TablesTableModel::columnCount(const QModelIndex &) const
{
return colCount;
}
Oid TablesTableModel::getType(int column) const
{
Oid oid;
switch (column) {
case TotalSizeCol:
case TableSizeCol:
case IndexSizeCol:
case ToastSizeCol:
oid = Pgsql::int8_oid;
break;
case TablespaceCol:
case OwnerCol:
case NameCol:
case NamespaceCol:
case KindCol:
case OptionsCol:
case AclCol:
case CommentCol:
default:
oid = Pgsql::varchar_oid;
}
return oid;
}
QVariant TablesTableModel::getData(const QModelIndex &index) const
{
const auto &table = m_tables[index.row()];
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;
}
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)
return getData(index);
else if (role == CustomDataTypeRole)
return getType(index.column());
else if (role == CustomDataMeaningRole) {
switch (index.column()) {
case TotalSizeCol:
case TableSizeCol:
case IndexSizeCol:
case ToastSizeCol:
return static_cast<int>(DataMeaningBytes);
default:
return static_cast<int>(DataMeaningNormal);
}
}
return QVariant();
}
void TablesTableModel::StartLoadTableSizes(std::map<Oid, int> oidIndex)
{
QPointer p(this);
QtConcurrent::run([this]
{
return QueryTableSizes();
})
.then(qApp, [p, oidIndex] (TableSizes sizes)
{
if (p)
{
p.data()->PopulateSizes(std::move(oidIndex), std::move(sizes));
}
});
}
TablesTableModel::TableSizes TablesTableModel::QueryTableSizes() const
{
std::string nsfilter;
switch (m_namespaceFilter)
{
case NamespaceFilter::User:
nsfilter = "(NOT (nspname LIKE 'pg_%' OR nspname='information_schema'))";
break;
case NamespaceFilter::PgCatalog:
nsfilter = "nspname = 'pg_catalog'";
break;
case NamespaceFilter::InformationSchema:
nsfilter = "nspname = 'information_schema'";
break;
}
std::string q =
"SELECT pg_class.oid, "
" pg_total_relation_size(pg_class.oid) AS total_bytes, "
" CASE WHEN relkind='r' THEN pg_indexes_size(pg_class.oid) ELSE 0 END AS index_bytes, "
" CASE WHEN relkind='r' THEN pg_total_relation_size(reltoastrelid) ELSE 0 END AS toast_bytes "
"\nFROM pg_catalog.pg_class \n"
" JOIN pg_namespace ON (relnamespace = pg_namespace.oid)"
" LEFT JOIN pg_catalog.pg_description AS d ON (objoid=pg_class.oid AND objsubid=0) \n"
"WHERE relkind IN ('r', 'p', 'm') AND " + nsfilter;
;
Pgsql::Connection connection;
connection.connect(openDatabase->config().connectionString());
Pgsql::Result sizesResult = connection.query(q.c_str());
TablesTableModel::TableSizes sizes;
sizes.reserve(sizesResult.rows());
for (const Pgsql::Row& row : sizesResult)
{
TableSize size;
size.oid = row.get(0);
size.totalBytes = row.get(1);
size.indexBytes = row.get(2);
size.toastBytes = row.get(3);
sizes.push_back(size);
}
return sizes;
}
void TablesTableModel::PopulateSizes(std::map<Oid, int> oidIndex, std::vector<TableSize> sizes)
{
for (auto s : sizes)
{
auto findIter = oidIndex.find(s.oid);
if (findIter != oidIndex.end())
{
m_tables[findIter->second].sizes = s;
}
}
emit dataChanged(
createIndex(0, TotalSizeCol),
createIndex(static_cast<int>(m_tables.size()), ToastSizeCol)
);
}

View file

@ -0,0 +1,95 @@
#ifndef TABLESTABLEMODEL_H
#define TABLESTABLEMODEL_H
#include "BaseTableModel.h"
#include "NamespaceFilter.h"
#include "catalog/PgClass.h"
#include <memory>
#include <vector>
class OpenDatabase;
class PgClass;
class PgDatabaseCatalog;
class TablesTableModel: public QAbstractTableModel {
public:
using RowItem = PgClass;
enum e_Columns : int {
NameCol, ///< either table, ns.table or table (ns) depending on settings/filters
NamespaceCol,
KindCol,
OwnerCol,
TablespaceCol,
OptionsCol,
AclCol,
CommentCol,
TotalSizeCol,
TableSizeCol,
IndexSizeCol,
ToastSizeCol,
colCount };
TablesTableModel(std::shared_ptr<OpenDatabase> opendatabase, QObject *parent);
void setNamespaceFilter(NamespaceFilter nsf);
void setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat);
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
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
{
return getTable(row);
}
Oid getTableOid(int row) const;
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>;
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
NamespaceFilter m_namespaceFilter = NamespaceFilter::User;
t_Tables m_tables;
QMetaObject::Connection refreshConnection;
std::shared_ptr<OpenDatabase> openDatabase;
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);
private slots:
void refresh();
};
#endif // TABLESTABLEMODEL_H

View file

@ -0,0 +1,109 @@
#include "TriggerTableModel.h"
#include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgTriggerContainer.h"
#include "CustomDataRole.h"
#include "ScopeGuard.h"
TriggerTableModel::TriggerTableModel(QObject *parent)
: QAbstractTableModel(parent)
{
}
QVariant TriggerTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
switch (section) {
case NameCol: return tr("Name");
case EventsCol: return tr("Events");
case WhenCol: return tr("When");
case DeferrableCol: return tr("Df");
case InitiallyCol: return tr("ID");
case ForCol: return tr("For");
case CondCol: return tr("Cond.");
// case ReferencingCol: return tr("Referencing");
case ProcedureCol: return tr("Function");
}
}
}
return QVariant();
}
void TriggerTableModel::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
{
if (cat != m_catalog) {
m_catalog = cat;
refreshConnection = connect(m_catalog.get(), &PgDatabaseCatalog::refreshed, this,
&TriggerTableModel::refresh);
}
refresh();
}
int TriggerTableModel::rowCount(const QModelIndex &) const
{
return m_triggers ? static_cast<int>(m_triggers->count()) : 0;
}
int TriggerTableModel::columnCount(const QModelIndex &) const
{
return colCount;
}
QVariant TriggerTableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
return getData(index);
else if (role == CustomDataTypeRole)
return getType(index.column());
else if (role == FirstHiddenValue) {
auto&& t = m_triggers->getByIdx(index.row());
return t.relid; //
}
return QVariant();
}
PgTrigger TriggerTableModel::trigger(int row) const
{
return m_triggers->getByIdx(row);
}
Oid TriggerTableModel::getType(int column) const
{
switch (column) {
case DeferrableCol:
case InitiallyCol:
return Pgsql::bool_oid;
}
return Pgsql::varchar_oid;
}
QVariant TriggerTableModel::getData(const QModelIndex &index) const
{
auto&& t = m_triggers->getByIdx(index.row());
switch (index.column()) {
case NameCol: return t.objectName();
case EventsCol: return t.eventAbbr();
case WhenCol: return t.typeFireWhen();
case DeferrableCol: return t.deferrable;
case InitiallyCol: return t.initdeferred;
case ForCol: return t.forEach();
case CondCol: return t.whenclause;
// case ReferencingCol: return tr("Referencing");
case ProcedureCol: return t.procedure();
}
return QVariant();
}
void TriggerTableModel::refresh()
{
beginResetModel();
SCOPE_EXIT { endResetModel(); };
m_triggers = m_catalog->triggers();
}

View file

@ -0,0 +1,79 @@
#ifndef TRIGGERTABLEMODEL_H
#define TRIGGERTABLEMODEL_H
#include <QAbstractTableModel>
#include "catalog/PgClass.h"
#include "catalog/PgTrigger.h"
#include <memory>
class PgDatabaseCatalog;
class PgTriggerContainer;
/**
* @brief The TriggerTableModel class
*
* Hidden values:
* - FirstHiddenValue: oid of table the trigger belongs to
*/
class TriggerTableModel: public QAbstractTableModel {
Q_OBJECT
public:
//using QAbstractTableModel::QAbstractTableModel;
enum e_Columns : int {
NameCol, //
EventsCol, // Insert, Update, Delete Truncate
WhenCol, // before after instead of
DeferrableCol,
InitiallyCol,
ForCol,
CondCol,
//ReferencingCol,
ProcedureCol,
colCount
};
TriggerTableModel(QObject *parent = nullptr);
// CREATE [ CONSTRAINT ] TRIGGER name { BEFORE | AFTER | INSTEAD OF } { event [ OR ... ] }
// ON table_name
// [ FROM referenced_table_name ]
// [ NOT DEFERRABLE | [ DEFERRABLE ] [ INITIALLY IMMEDIATE | INITIALLY DEFERRED ] ]
// [ REFERENCING { { OLD | NEW } TABLE [ AS ] transition_relation_name } [ ... ] ]
// [ FOR [ EACH ] { ROW | STATEMENT } ]
// [ WHEN ( condition ) ]
// EXECUTE PROCEDURE function_name ( arguments )
// where event can be one of:
// INSERT
// UPDATE [ OF column_name [, ... ] ]
// DELETE
// TRUNCATE
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
void setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat);
// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex &index, int role) const override;
PgTrigger trigger(int row) const;
private:
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
std::shared_ptr<const PgTriggerContainer> m_triggers;
QMetaObject::Connection refreshConnection;
Oid getType(int column) const;
QVariant getData(const QModelIndex &index) const;
private slots:
void refresh();
};
#endif // TRIGGERTABLEMODEL_H

View file

@ -0,0 +1,46 @@
#include "catalog/widgets/CatalogConstraintPage.h"
#include "catalog/models/ConstraintModel.h"
#include "CustomFilterSortModel.h"
#include "catalog/delegates/IconColumnDelegate.h"
#include "util/PgLabTableView.h"
#include "SqlCodePreview.h"
#include <QHeaderView>
#include <QStringBuilder>
CatalogConstraintPage::CatalogConstraintPage(QWidget *parent)
: CatalogPageBase(parent)
{
m_constraintModel = new ConstraintModel(this);
m_sortFilterProxy->setSourceModel(m_constraintModel);
m_tableView->setItemDelegateForColumn(0, new IconColumnDelegate(this));
m_tableView->horizontalHeader()->setSortIndicator(ConstraintModel::NameCol, Qt::AscendingOrder);
m_tableView->setSortingEnabled(true);
connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &CatalogConstraintPage::tableView_selectionChanged);
connect(m_constraintModel, &ConstraintModel::modelReset, m_definitionView, &SqlCodePreview::clear);
}
void CatalogConstraintPage::catalogSet()
{
}
void CatalogConstraintPage::setFilter(const std::optional<PgClass> &cls)
{
m_constraintModel->setData(m_catalog, cls);
m_tableView->resizeColumnsToContents();
}
void CatalogConstraintPage::tableView_selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
{
auto rijen = selectedRows();
QString drops;
QString creates;
for (auto rij : rijen) {
const PgConstraint constraint = m_constraintModel->constraint(rij);
drops += constraint.dropSql() % "\n";
creates += constraint.createSql() % "\n";
}
m_definitionView->setPlainText(drops % "\n" % creates);
}

View file

@ -0,0 +1,29 @@
#ifndef CATALOGCONSTRAINTPAGE_H
#define CATALOGCONSTRAINTPAGE_H
#include "CatalogPageBase.h"
class ConstraintModel;
class PgClass;
class QItemSelection;
class CatalogConstraintPage : public CatalogPageBase {
Q_OBJECT
public:
explicit CatalogConstraintPage(QWidget *parent = nullptr);
void setFilter(const std::optional<PgClass> &cls);
protected:
void catalogSet() override;
private:
ConstraintModel *m_constraintModel = nullptr;
private slots:
void tableView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
};
#endif // CATALOGCONSTRAINTPAGE_H

View file

@ -0,0 +1,100 @@
#include "CatalogFunctionsPage.h"
#include "ResultTableModelUtil.h"
#include "CustomFilterSortModel.h"
#include "CustomDataRole.h"
#include "util/PgLabItemDelegate.h"
#include "catalog/models/ProcTableModel.h"
#include "SqlCodePreview.h"
#include <QApplication>
#include "util/PgLabTableView.h"
#include <QHeaderView>
#include <QVBoxLayout>
#include <QTabWidget>
CatalogFunctionsPage::CatalogFunctionsPage(QWidget *parent)
: QSplitter(Qt::Horizontal, parent)
{
// create widgets
m_functionTable = new PgLabTableView(this);
m_detailTabs = new QTabWidget(this);
m_definitionView = new SqlCodePreview(this);
// build widget tree
// add top level widgets to splitter
addWidget(m_functionTable);
addWidget(m_detailTabs);
// add widgets to detail tabs
m_detailTabs->addTab(m_definitionView, "SQL");
// auto mainLayout = new QVBoxLayout;
// mainLayout->addWidget(m_functionTable);
// setLayout(mainLayout);
// Do further initialization of widgets and models
m_model = new ProcTableModel(this);
m_sortFilterProxy = new CustomFilterSortModel(this);
m_sortFilterProxy->setSourceModel(m_model);
m_functionTable->setModel(m_sortFilterProxy);
m_functionTable->horizontalHeader()->setSortIndicator(0, Qt::AscendingOrder);
m_functionTable->setSortingEnabled(true);
m_functionTable->setSelectionBehavior(QAbstractItemView::SelectRows);
m_functionTable->setSelectionMode(QAbstractItemView::SingleSelection);
connect(m_functionTable->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
&CatalogFunctionsPage::functionTable_currentRowChanged);
connect(m_model, &ProcTableModel::modelReset, m_definitionView, &SqlCodePreview::clear);
retranslateUi();
}
void CatalogFunctionsPage::retranslateUi()
{
auto set_tabtext = [this] (QWidget *widget, QString translation) {
m_detailTabs->setTabText(m_detailTabs->indexOf(widget), translation);
};
set_tabtext(m_definitionView, QApplication::translate("FunctionsPage", "SQL", nullptr));
}
void CatalogFunctionsPage::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
{
m_catalog = cat;
m_model->setCatalog(cat);
m_functionTable->resizeColumnsToContents();
}
void CatalogFunctionsPage::setNamespaceFilter(NamespaceFilter filter)
{
m_model->setNamespaceFilter(filter);
}
void CatalogFunctionsPage::functionTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{
if (current.row() != previous.row()) {
if (current.isValid()) {
auto source_index = m_sortFilterProxy->mapToSource(current);
auto proc = m_model->proc(source_index.row());
selectedProcChanged(proc);
}
else
selectedProcChanged({});
}
}
void CatalogFunctionsPage::selectedProcChanged(const std::optional<PgProc> &proc)
{
updateSqlTab(proc);
}
void CatalogFunctionsPage::updateSqlTab(const std::optional<PgProc> &proc)
{
if (!proc.has_value()) {
m_definitionView->clear();
return;
}
QString create_sql = proc->createSql();
m_definitionView->setPlainText(create_sql);
}

View file

@ -0,0 +1,43 @@
#ifndef FUNCTIONSPAGE_H
#define FUNCTIONSPAGE_H
#include <QSplitter>
#include <memory>
#include <optional>
#include "NamespaceFilter.h"
class PgLabTableView;
class PgDatabaseCatalog;
class ProcTableModel;
class CustomFilterSortModel;
class QTabWidget;
class SqlCodePreview;
class PgProc;
class CatalogFunctionsPage : public QSplitter {
Q_OBJECT
public:
explicit CatalogFunctionsPage(QWidget *parent = nullptr);
void setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat);
void setNamespaceFilter(NamespaceFilter filter);
signals:
public slots:
void functionTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
private:
PgLabTableView *m_functionTable = nullptr;
QTabWidget *m_detailTabs = nullptr;
SqlCodePreview *m_definitionView = nullptr;
ProcTableModel *m_model = nullptr;
CustomFilterSortModel *m_sortFilterProxy = nullptr;
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
void retranslateUi();
void selectedProcChanged(const std::optional<PgProc> &proc);
void updateSqlTab(const std::optional<PgProc> &proc);
};
#endif // FUNCTIONSPAGE_H

View file

@ -0,0 +1,46 @@
#include "catalog/widgets/CatalogIndexPage.h"
#include "CustomFilterSortModel.h"
#include "catalog/models/IndexModel.h"
#include "util/PgLabTableView.h"
#include "SqlCodePreview.h"
#include <QHeaderView>
#include <QStringBuilder>
#include "catalog/delegates/IconColumnDelegate.h"
CatalogIndexPage::CatalogIndexPage(QWidget *parent)
: CatalogPageBase(parent)
{
m_indexModel = new IndexModel(this);
m_sortFilterProxy->setSourceModel(m_indexModel);
m_tableView->setItemDelegateForColumn(0, new IconColumnDelegate(this));
m_tableView->horizontalHeader()->setSortIndicator(IndexModel::NameCol, Qt::AscendingOrder);
m_tableView->setSortingEnabled(true);
connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &CatalogIndexPage::tableView_selectionChanged);
connect(m_indexModel, &IndexModel::modelReset, m_definitionView, &SqlCodePreview::clear);
}
void CatalogIndexPage::catalogSet()
{
}
void CatalogIndexPage::setFilter(const std::optional<PgClass> &cls)
{
m_indexModel->setData(m_catalog, cls);
m_tableView->resizeColumnsToContents();
}
void CatalogIndexPage::tableView_selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
{
auto rijen = selectedRows();
QString drops;
QString creates;
for (auto rij : rijen) {
const PgIndex index = m_indexModel->getIndex(rij);
drops += index.dropSql() % "\n";
creates += index.createSql() % "\n";
}
m_definitionView->setPlainText(drops % "\n" % creates);
}

View file

@ -0,0 +1,29 @@
#ifndef CATALOGINDEXPAGE_H
#define CATALOGINDEXPAGE_H
#include "CatalogPageBase.h"
class IndexModel;
class PgClass;
class QItemSelection;
class CatalogIndexPage : public CatalogPageBase {
Q_OBJECT
public:
explicit CatalogIndexPage(QWidget *parent = nullptr);
void setFilter(const std::optional<PgClass> &cls);
protected:
void catalogSet() override;
private:
IndexModel *m_indexModel = nullptr;
private slots:
void tableView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
};
#endif // CATALOGINDEXPAGE_H

View file

@ -0,0 +1,94 @@
#include "CatalogInspector.h"
#include "OpenDatabase.h"
#include "UserConfiguration.h"
#include "catalog/widgets/CatalogFunctionsPage.h"
#include "catalog/widgets/CatalogNamespacePage.h"
#include "catalog/widgets/CatalogSequencesPage.h"
#include "catalog/widgets/CatalogTablesPage.h"
#include "catalog/widgets/CatalogTypesPage.h"
#include <QApplication>
#include <QTabWidget>
#include <QStringBuilder>
#include <QVBoxLayout>
#include <unordered_set>
CatalogInspector::CatalogInspector(std::shared_ptr<OpenDatabase> open_database, QWidget *parent)
: QWidget(parent)
{
m_tabWidget = new QTabWidget(this);
// m_namespacePage = new CatalogNamespacePage(this);
m_tablesPage = new CatalogTablesPage(open_database, this);
m_functionsPage = new CatalogFunctionsPage(this);
m_sequencesPage = new CatalogSequencesPage(this);
m_typesPage = new CatalogTypesPage(this);
auto layout = new QVBoxLayout(this);
setLayout(layout);
layout->addWidget(m_tabWidget);
// m_tabWidget->addTab(m_namespacePage, "");
m_tabWidget->addTab(m_tablesPage, "");
m_tabWidget->addTab(m_functionsPage, "");
m_tabWidget->addTab(m_sequencesPage, "");
m_tabWidget->addTab(m_typesPage, "");
setCatalog(open_database->catalog());
retranslateUi(false);
}
void CatalogInspector::retranslateUi(bool all)
{
m_tablesPage->retranslateUi(all);
// m_tabWidget->setTabText(m_tabWidget->indexOf(m_namespacePage),
// QApplication::translate("CatalogInspector", "Schemas", nullptr));
m_tabWidget->setTabText(m_tabWidget->indexOf(m_tablesPage),
QApplication::translate("CatalogInspector", "Tables", nullptr));
m_tabWidget->setTabText(m_tabWidget->indexOf(m_functionsPage),
QApplication::translate("CatalogInspector", "Functions", nullptr));
m_tabWidget->setTabText(m_tabWidget->indexOf(m_sequencesPage),
QApplication::translate("CatalogInspector", "Sequences", nullptr));
m_tabWidget->setTabText(m_tabWidget->indexOf(m_typesPage),
QApplication::translate("CatalogInspector", "Types", nullptr));
}
CatalogInspector::~CatalogInspector()
{
}
void CatalogInspector::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
{
m_catalog = cat;
// m_namespacePage->setCatalog(cat);
m_tablesPage->setCatalog(cat);
m_functionsPage->setCatalog(cat);
m_sequencesPage->setCatalog(cat);
m_typesPage->setCatalog(cat);
}
void CatalogInspector::setNamespaceFilter(NamespaceFilter filter)
{
m_tablesPage->setNamespaceFilter(filter);
m_functionsPage->setNamespaceFilter(filter);
m_sequencesPage->setNamespaceFilter(filter);
QString hint = "Catalog instpector";
QString caption = "Inspector";
switch (filter) {
case NamespaceFilter::PgCatalog:
hint += " - pg_catalog";
caption = "pg_catalog";
break;
case NamespaceFilter::InformationSchema:
hint += " - information_schema";
caption = "information_schema";
break;
default:
break;
}
// context()->setCaption(this, caption, hint);
}
CatalogTablesPage *CatalogInspector::tablesPage()
{
return m_tablesPage;
}

View file

@ -0,0 +1,41 @@
#ifndef TABLESPAGE_H
#define TABLESPAGE_H
#include <QWidget>
#include <memory>
#include "NamespaceFilter.h"
class CatalogFunctionsPage;
class CatalogSequencesPage;
class CatalogTablesPage;
class CatalogNamespacePage;
class CatalogTypesPage;
class OpenDatabase;
class PgDatabaseCatalog;
class QTabWidget;
class CatalogInspector : public QWidget {
Q_OBJECT
public:
explicit CatalogInspector(std::shared_ptr<OpenDatabase> open_database, QWidget *parent = nullptr);
~CatalogInspector();
void setCatalog(std::shared_ptr<PgDatabaseCatalog> cat);
void setNamespaceFilter(NamespaceFilter filter);
CatalogTablesPage *tablesPage();
private:
QTabWidget *m_tabWidget = nullptr;
// CatalogNamespacePage *m_namespacePage = nullptr;
CatalogTablesPage *m_tablesPage = nullptr;
CatalogFunctionsPage *m_functionsPage = nullptr;
CatalogSequencesPage *m_sequencesPage = nullptr;
CatalogTypesPage *m_typesPage = nullptr;
std::shared_ptr<PgDatabaseCatalog> m_catalog;
void retranslateUi(bool all = true);
private slots:
};
#endif // TABLESPAGE_H

View file

@ -0,0 +1,32 @@
#include "CatalogNamespacePage.h"
#include <QTreeView>
#include "NamespaceItemModel.h"
#include "SqlCodePreview.h"
#include "catalog/PgDatabaseCatalog.h"
CatalogNamespacePage::CatalogNamespacePage(QWidget *parent)
: QSplitter(Qt::Horizontal, parent)
, m_namespaceTree(new QTreeView(this))
, m_model(new NamespaceItemModel(this))
{
m_namespaceTree->setModel(m_model);
m_definitionView = new SqlCodePreview(this);
addWidget(m_namespaceTree);
addWidget(m_definitionView);
retranslateUi();
}
void CatalogNamespacePage::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
{
m_catalog = cat;
m_model->setEnableCheckboxes(false);
m_model->init(cat->namespaces());
}
void CatalogNamespacePage::retranslateUi()
{
}

View file

@ -0,0 +1,36 @@
#ifndef CATALOGNAMESPACEPAGE_H
#define CATALOGNAMESPACEPAGE_H
#include "catalog/widgets/CatalogPageBase.h"
class QTreeView;
class NamespaceItemModel;
class PgDatabaseCatalog;
class SqlCodePreview;
class CatalogNamespacePage : public QSplitter
{
Q_OBJECT
public:
explicit CatalogNamespacePage(QWidget *parent = nullptr);
void setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat);
signals:
public slots:
protected:
private:
QTreeView *m_namespaceTree = nullptr;
SqlCodePreview *m_definitionView = nullptr;
NamespaceItemModel *m_model = nullptr;
CustomFilterSortModel *m_sortFilterProxy = nullptr;
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
void retranslateUi();
};
#endif // CATALOGNAMESPACEPAGE_H

View file

@ -0,0 +1,35 @@
#include "catalog/widgets/CatalogPageBase.h"
#include "CustomFilterSortModel.h"
#include "util/PgLabTableView.h"
#include "SqlCodePreview.h"
CatalogPageBase::CatalogPageBase(QWidget *parent)
: QSplitter(Qt::Vertical, parent)
{
m_tableView = new PgLabTableView(this);
m_definitionView = new SqlCodePreview(this);
addWidget(m_tableView);
addWidget(m_definitionView);
m_sortFilterProxy = new CustomFilterSortModel(this);
m_tableView->setModel(m_sortFilterProxy);
m_tableView->setSortingEnabled(true);
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
}
void CatalogPageBase::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
{
m_catalog = cat;
m_definitionView->setCatalog(m_catalog);
catalogSet();
}
std::unordered_set<int> CatalogPageBase::selectedRows() const
{
auto&& indexes = m_tableView->selectionModel()->selectedIndexes();
std::unordered_set<int> rijen;
for (const auto &e : indexes)
rijen.insert(m_sortFilterProxy->mapToSource(e).row());
return rijen;
}

View file

@ -0,0 +1,32 @@
#ifndef CATALOGPAGEBASE_H
#define CATALOGPAGEBASE_H
#include <QSplitter>
#include <memory>
#include <optional>
#include <unordered_set>
class PgDatabaseCatalog;
class PgLabTableView;
class SqlCodePreview;
class CustomFilterSortModel;
class CatalogPageBase : public QSplitter {
Q_OBJECT
public:
CatalogPageBase(QWidget *parent = nullptr);
void setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat);
protected:
PgLabTableView *m_tableView = nullptr;
SqlCodePreview *m_definitionView = nullptr;
CustomFilterSortModel *m_sortFilterProxy = nullptr;
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
virtual void catalogSet() {}
std::unordered_set<int> selectedRows() const;
};
#endif // CATALOGPAGEBASE_H

View file

@ -0,0 +1,83 @@
#include "catalog/widgets/CatalogSequencesPage.h"
#include "ResultTableModelUtil.h"
#include "CustomFilterSortModel.h"
#include "CustomDataRole.h"
#include "util/PgLabItemDelegate.h"
#include "catalog/models/SequenceModel.h"
#include "SqlCodePreview.h"
#include "util/PgLabTableView.h"
#include <QHeaderView>
CatalogSequencesPage::CatalogSequencesPage(QWidget *parent)
: QSplitter(Qt::Horizontal, parent)
{
m_sequenceTable = new PgLabTableView(this);
m_definitionView = new SqlCodePreview(this);
// build widget tree
// add top level widgets to splitter
addWidget(m_sequenceTable);
addWidget(m_definitionView);
m_model = new SequenceModel(this);
m_sortFilterProxy = new CustomFilterSortModel(this);
m_sortFilterProxy->setSourceModel(m_model);
m_sequenceTable->setModel(m_sortFilterProxy);
m_sequenceTable->horizontalHeader()->setSortIndicator(SequenceModel::NameCol, Qt::AscendingOrder);
m_sequenceTable->setSortingEnabled(true);
m_sequenceTable->setSelectionBehavior(QAbstractItemView::SelectRows);
m_sequenceTable->setSelectionMode(QAbstractItemView::SingleSelection);
connect(m_sequenceTable->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
&CatalogSequencesPage::sequenceTable_currentRowChanged);
connect(m_model, &SequenceModel::modelReset,
[this] () { selectedSequenceChanged({}); });
retranslateUi();
}
void CatalogSequencesPage::retranslateUi()
{
}
void CatalogSequencesPage::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
{
m_catalog = cat;
m_model->setCatalog(cat);
m_sequenceTable->resizeColumnsToContents();
}
void CatalogSequencesPage::setNamespaceFilter(NamespaceFilter filter)
{
m_model->setNamespaceFilter(filter);
}
void CatalogSequencesPage::sequenceTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{
if (current.row() != previous.row()) {
if (current.isValid()) {
auto source_index = m_sortFilterProxy->mapToSource(current);
auto proc = m_model->sequence(source_index.row());
selectedSequenceChanged(proc);
}
else
selectedSequenceChanged({});
}
}
void CatalogSequencesPage::selectedSequenceChanged(const std::optional<PgSequence> &seq)
{
updateSqlTab(seq);
}
void CatalogSequencesPage::updateSqlTab(const std::optional<PgSequence> &seq)
{
if (!seq.has_value()) {
m_definitionView->clear();
return;
}
QString create_sql = seq->createSql();
m_definitionView->setPlainText(create_sql);
}

View file

@ -0,0 +1,40 @@
#ifndef SEQUENCESPAGES_H
#define SEQUENCESPAGES_H
#include "NamespaceFilter.h"
#include <QSplitter>
#include <memory>
#include <optional>
class PgLabTableView;
class PgDatabaseCatalog;
class SequenceModel;
class CustomFilterSortModel;
class SqlCodePreview;
class PgSequence;
class CatalogSequencesPage : public QSplitter {
Q_OBJECT
public:
CatalogSequencesPage(QWidget *parent = nullptr);
void setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat);
void setNamespaceFilter(NamespaceFilter filter);
public slots:
void sequenceTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
private:
PgLabTableView *m_sequenceTable = nullptr;
//QTabWidget *m_detailTabs = nullptr;
SqlCodePreview *m_definitionView = nullptr;
SequenceModel *m_model = nullptr;
CustomFilterSortModel *m_sortFilterProxy = nullptr;
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
void retranslateUi();
void selectedSequenceChanged(const std::optional<PgSequence> &seq);
void updateSqlTab(const std::optional<PgSequence> &seq);
};
#endif // SEQUENCESPAGES_H

View file

@ -0,0 +1,205 @@
#include "CatalogTablesPage.h"
#include "catalog/widgets/CatalogConstraintPage.h"
#include "catalog/widgets/CatalogIndexPage.h"
#include "catalog/widgets/ColumnPage.h"
#include "catalog/widgets/DependantsPage.h"
#include "PropertiesPage.h"
#include "catalog/widgets/TriggerPage.h"
#include "catalog/models/ColumnTableModel.h"
#include "catalog/models/ConstraintModel.h"
#include "catalog/models/TablesTableModel.h"
#include "util/PgLabTableView.h"
#include "ResultTableModelUtil.h"
#include "SqlCodePreview.h"
#include "SqlFormattingUtils.h"
#include "catalog/PgAttributeContainer.h"
#include "catalog/PgIndexContainer.h"
#include "catalog/PgTriggerContainer.h"
#include <QApplication>
#include <QHeaderView>
#include <QStringBuilder>
//#include <QSortFilterProxyModel>
#include <QTableWidget>
CatalogTablesPage::CatalogTablesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget *parent)
: QSplitter(Qt::Horizontal, parent)
, m_tablesTableView(this, new TablesTableModel(opendatabase, this))
{
auto tv = m_tablesTableView.tableView();
tv->setSelectionMode(QAbstractItemView::SingleSelection);
m_detailsTabs = new QTabWidget(this);
// Populate splitter
addWidget(tv);
addWidget(m_detailsTabs);
// - Columns page
m_columnsPage = new ColumnPage(this);
m_detailsTabs->addTab(m_columnsPage, "");
// constrainst
m_constraintPage = new CatalogConstraintPage(this);
m_detailsTabs->addTab(m_constraintPage, "");
// - Index page
m_indexPage = new CatalogIndexPage(this);
m_detailsTabs->addTab(m_indexPage, "");
// - Properties page
// m_propertiesPage = new PropertiesPage(this);
// m_propertiesPage->setSourceModel(m_tablesTableView.dataModel());
// m_detailsTabs->addTab(m_propertiesPage, "");
// - Trigger page
m_triggerPage = new TriggerPage(this);
m_detailsTabs->addTab(m_triggerPage, "");
m_dependentsPage = new DependantsPage(this);
m_detailsTabs->addTab(m_dependentsPage, "");
// SQL tab
m_tableSql = new SqlCodePreview(this);
m_detailsTabs->addTab(m_tableSql, "");
// Force focus on columns tab by default
m_detailsTabs->setCurrentIndex(0);
// Signals
connect(tv->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
&CatalogTablesPage::tableListTable_currentRowChanged);
connect(m_tablesTableView.dataModel(), &QAbstractItemModel::layoutChanged,
this, &CatalogTablesPage::tableListTable_layoutChanged);
connect(tv, &QTableView::doubleClicked,
this, &CatalogTablesPage::on_tableListTable_doubleClicked);
}
void CatalogTablesPage::retranslateUi(bool /*all*/)
{
auto set_tabtext = [this] (QWidget *widget, QString translation) {
m_detailsTabs->setTabText(m_detailsTabs->indexOf(widget), translation);
};
set_tabtext(m_columnsPage, QApplication::translate("TablesPage", "Columns", nullptr));
set_tabtext(m_constraintPage, QApplication::translate("TablesPage", "Constraints", nullptr));
set_tabtext(m_indexPage, QApplication::translate("TablesPage", "Indexes", nullptr));
// set_tabtext(m_propertiesPage, QApplication::translate("TablesPage", "Properties", nullptr));
set_tabtext(m_triggerPage, QApplication::translate("TablesPage", "Triggers", nullptr));
set_tabtext(m_dependentsPage, QApplication::translate("TablesPage", "Dependants", nullptr));
set_tabtext(m_tableSql, QApplication::translate("TablesPage", "SQL", nullptr));
}
void CatalogTablesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
{
m_catalog = cat;
m_tablesTableView.setCatalog(cat);
m_constraintPage->setCatalog(cat);
m_indexPage->setCatalog(cat);
m_triggerPage->setCatalog(cat);
m_dependentsPage->setCatalog(cat);
}
void CatalogTablesPage::setNamespaceFilter(NamespaceFilter filter)
{
m_tablesTableView.dataModel()->setNamespaceFilter(filter);
m_tablesTableView.tableView()->resizeColumnsToContents();
}
void CatalogTablesPage::tableListTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{
if (current.row() == previous.row())
return;
auto table = m_tablesTableView.rowItemForProxyIndex(current);
selectedTableChanged(table);
}
void CatalogTablesPage::tableListTable_layoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint )
{
auto table = m_tablesTableView.currentRowItem();
selectedTableChanged(table);
}
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());
}
}
void CatalogTablesPage::selectedTableChanged(const std::optional<PgClass> &table)
{
m_columnsPage->setData(m_catalog, table);
m_constraintPage->setFilter(table);
m_indexPage->setFilter(table);
m_triggerPage->setFilter(table);
m_dependentsPage->setFilter(table);
updateSqlTab(table);
}
void CatalogTablesPage::updateSqlTab(const std::optional<PgClass> &table)
{
if (!table.has_value()) {
m_tableSql->clear();
return;
}
QString drop_sql;
QString create_sql;
// table
drop_sql += table->dropSql() % "\n";
create_sql += table->createSql() % "\n";
// - columns
// - constraints
// table details (inherits etc)
// Indexes
auto && indexes = m_catalog->indexes()->getIndexesForTable(table->oid());
if (!indexes.empty()) {
drop_sql += "-- drop Indexes\n";
create_sql += "-- create Indexes\n";
for (auto && index : indexes) {
drop_sql += index.dropSql() % "\n";
create_sql += index.createSql() % "\n";
}
}
// Triggers
auto && triggers = m_catalog->triggers()->getTriggersForRelation(table->oid());
if (!triggers.empty()) {
drop_sql += "-- drop Triggers\n";
create_sql += "-- create Triggers\n";
for (auto && trg : triggers) {
drop_sql += trg.dropSql() % "\n";
create_sql += trg.createSql() % "\n";
}
}
// Privileges
create_sql += "-- set Privileges\n";
create_sql += table->grantSql() % "\n";
// Comments
create_sql += "-- set Comments table + columns\n";
create_sql += table->commentSql() % "\n";
auto && cols = m_catalog->attributes()->getColumnsForRelation(table->oid());
for (auto && col : cols) {
if (!col.description.isEmpty()) {
create_sql += "COMMENT ON COLUMN " + table->fullyQualifiedQuotedObjectName()
+ "." + quoteIdent(col.name) + " IS " + dollarQuoteString(col.description) + ";\n";
}
}
//
m_tableSql->setPlainText(drop_sql % "\n\n" % create_sql);
}

View file

@ -0,0 +1,66 @@
#ifndef CATALOGTABLESPAGE_H
#define CATALOGTABLESPAGE_H
#include "NamespaceFilter.h"
#include "catalog/models/TablesTableModel.h"
#include "util/PgLabTableViewHelper.h"
#include <QSplitter>
#include <memory>
#include <optional>
#include <QAbstractItemModel>
#include "Pgsql_oids.h"
class CatalogConstraintPage;
class CatalogIndexPage;
class ColumnPage;
class ColumnTableModel;
class ConstraintModel;
class DependantsPage;
class PgClass;
class PgDatabaseCatalog;
class PgLabTableView;
class PropertiesPage;
class QTabWidget;
class SqlCodePreview;
class QSortFilterProxyModel;
class TriggerPage;
class CatalogTablesPage: public QSplitter {
Q_OBJECT
public:
explicit CatalogTablesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget * parent = nullptr);
void setCatalog(std::shared_ptr<PgDatabaseCatalog> cat);
void setNamespaceFilter(NamespaceFilter filter);
void retranslateUi(bool all = true);
signals:
void tableSelected(Oid tableoid);
private:
PgLabTableViewHelper<TablesTableModel> m_tablesTableView;
// Details
QTabWidget *m_detailsTabs = nullptr;
ColumnPage *m_columnsPage = nullptr;
CatalogConstraintPage *m_constraintPage = nullptr;
CatalogIndexPage *m_indexPage = nullptr;
// PropertiesPage *m_propertiesPage = nullptr;
TriggerPage *m_triggerPage = nullptr;
DependantsPage *m_dependentsPage = nullptr;
SqlCodePreview *m_tableSql = nullptr;
std::shared_ptr<PgDatabaseCatalog> m_catalog;
void selectedTableChanged(const std::optional<PgClass> &table);
void updateSqlTab(const std::optional<PgClass> &table);
private slots:
void tableListTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
void tableListTable_layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
void on_tableListTable_doubleClicked(const QModelIndex &index);
};
#endif // CATALOGTABLESPAGE_H

View file

@ -0,0 +1,80 @@
#include "CatalogTypesPage.h"
#include "ResultTableModelUtil.h"
#include "CustomFilterSortModel.h"
#include "CustomDataRole.h"
#include "util/PgLabItemDelegate.h"
#include "catalog/PgType.h"
#include "model/TypeSelectionItemModel.h"
#include "SqlCodePreview.h"
#include "util/PgLabTableView.h"
#include <optional>
#include <QHeaderView>
CatalogTypesPage::CatalogTypesPage(QWidget *parent)
: QSplitter(Qt::Horizontal, parent)
{
m_typeTable = new PgLabTableView(this);
m_definitionView = new SqlCodePreview(this);
// build widget tree
// add top level widgets to splitter
addWidget(m_typeTable);
addWidget(m_definitionView);
m_model = new TypeModel(this);
m_sortFilterProxy = new CustomFilterSortModel(this);
m_sortFilterProxy->setSourceModel(m_model);
m_typeTable->setModel(m_sortFilterProxy);
m_typeTable->horizontalHeader()->setSortIndicator(TypeModel::NameCol, Qt::AscendingOrder);
m_typeTable->setSortingEnabled(true);
m_typeTable->setSelectionBehavior(QAbstractItemView::SelectRows);
m_typeTable->setSelectionMode(QAbstractItemView::SingleSelection);
connect(m_typeTable->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
&CatalogTypesPage::typeTable_currentRowChanged);
connect(m_model, &TypeModel::modelReset,
[this] () { selectedTypeChanged({}); });
retranslateUi();
}
void CatalogTypesPage::retranslateUi()
{
}
void CatalogTypesPage::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
{
m_catalog = cat;
m_model->setTypeList(cat->types());
m_typeTable->resizeColumnsToContents();
}
void CatalogTypesPage::typeTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{
if (current.row() != previous.row()) {
if (current.isValid()) {
auto source_index = m_sortFilterProxy->mapToSource(current);
auto proc = m_model->typ(source_index.row());
selectedTypeChanged(proc);
}
else
selectedTypeChanged({});
}
}
void CatalogTypesPage::selectedTypeChanged(const std::optional<PgType> &typ)
{
updateSqlTab(typ);
}
void CatalogTypesPage::updateSqlTab(const std::optional<PgType> &typ)
{
if (!typ.has_value()) {
m_definitionView->clear();
return;
}
QString create_sql = typ->createSql();
m_definitionView->setPlainText(create_sql);
}

View file

@ -0,0 +1,34 @@
#pragma once
#include <QSplitter>
class PgLabTableView;
class PgDatabaseCatalog;
class TypeModel;
class CustomFilterSortModel;
class SqlCodePreview;
class PgType;
class CatalogTypesPage : public QSplitter
{
Q_OBJECT
public:
CatalogTypesPage(QWidget *parent = nullptr);
void setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat);
public slots:
void typeTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
private:
PgLabTableView *m_typeTable = nullptr;
//QTabWidget *m_detailTabs = nullptr;
SqlCodePreview *m_definitionView = nullptr;
TypeModel *m_model = nullptr;
CustomFilterSortModel *m_sortFilterProxy = nullptr;
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
void retranslateUi();
void selectedTypeChanged(const std::optional<PgType> &seq);
void updateSqlTab(const std::optional<PgType> &seq);
};

View file

@ -0,0 +1,109 @@
#include "catalog/widgets/ColumnPage.h"
#include "catalog/models/ColumnTableModel.h"
#include "CustomFilterSortModel.h"
#include "CustomDataRole.h"
#include "util/PgLabTableView.h"
#include "ResultTableModelUtil.h"
#include "SqlCodePreview.h"
#include "SqlFormattingUtils.h"
#include "UserConfiguration.h"
#include "catalog/PgClass.h"
#include <QHeaderView>
#include <QSortFilterProxyModel>
#include <QStyledItemDelegate>
#include <QStringBuilder>
#include <unordered_set>
ColumnPage::ColumnPage(QWidget *parent)
: QSplitter(Qt::Vertical, parent)
{
m_tableView = new PgLabTableView(this);
m_definitionView = new SqlCodePreview(this);
addWidget(m_tableView);
addWidget(m_definitionView);
m_columnModel = new ColumnTableModel(this);
m_sortFilterProxy = new QSortFilterProxyModel(this);
m_sortFilterProxy->setSourceModel(m_columnModel);
m_tableView->setItemDelegateForColumn(ColumnTableModel::TypeCol, new QStyledItemDelegate(this));
m_tableView->setModel(m_sortFilterProxy);
m_tableView->horizontalHeader()->setSortIndicator(ColumnTableModel::AttnumCol, Qt::AscendingOrder);
m_tableView->setSortingEnabled(true);
m_sortFilterProxy->sort(ColumnTableModel::AttnumCol, Qt::AscendingOrder);
connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &ColumnPage::tableView_selectionChanged);
connect(m_columnModel, &ColumnTableModel::modelReset, m_definitionView, &SqlCodePreview::clear);
}
void ColumnPage::setData(std::shared_ptr<const PgDatabaseCatalog> cat, const std::optional<PgClass> &cls)
{
m_catalog = cat;
m_definitionView->setCatalog(cat);
m_columnModel->setData(cat, cls);
m_Class = cls;
m_tableView->resizeColumnsToContents();
}
void ColumnPage::tableView_selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
{
auto&& indexes = m_tableView->selectionModel()->selectedIndexes();
std::unordered_set<int> rijen;
for (const auto &e : indexes)
rijen.insert(m_sortFilterProxy->mapToSource(e).row());
const QString alterTable = "ALTER TABLE " % m_Class->fullyQualifiedQuotedObjectName();
QString completeSql;
if (!rijen.empty()) {
QString drops;
QString addsql;
auto iter = rijen.begin();
if (iter != rijen.end())
{
auto && col = m_columnModel->column(*iter);
drops = alterTable % "\n DROP COLUMN " % quoteIdent(col.name);
addsql = alterTable % "\n ADD COLUMN " % col.columnDefinition(*m_catalog);
for (++iter; iter != rijen.end(); ++iter)
{
auto && col = m_columnModel->column(*iter);
drops += ",\n DROP COLUMN " % quoteIdent(col.name);
addsql += ",\n ADD COLUMN " % col.columnDefinition(*m_catalog);
}
drops += ";";
addsql += ";";
m_definitionView->setPlainText(drops % "\n\n" % addsql);
completeSql += drops % "\n\n" % addsql % "\n\n";
}
for (auto r : rijen)
{
auto && col = m_columnModel->column(r);
auto cs = col.commentStatement(*m_catalog, m_Class.value());
if (!cs.isEmpty())
completeSql += cs % "\n";
}
completeSql += "\n-- SQL to correct just the defaults\n";
for (auto r : rijen)
{
auto && col = m_columnModel->column(r);
completeSql += alterTable % " ALTER COLUMN " % quoteIdent(col.name);
if (col.hasdef)
completeSql += " SET DEFAULT " % col.defaultValue % ";\n";
else
completeSql += " DROP DEFAULT;\n";
}
completeSql += "\n-- SQL to correct NULLABLE\n";
for (auto r : rijen)
{
auto && col = m_columnModel->column(r);
completeSql += alterTable % " ALTER COLUMN " % quoteIdent(col.name);
if (col.notnull)
completeSql += " SET NOT NULL;\n";
else
completeSql += " DROP NOT NULL;\n";
}
}
m_definitionView->setPlainText(completeSql);
}

View file

@ -0,0 +1,42 @@
#ifndef COLUMNPAGE_H
#define COLUMNPAGE_H
#include "catalog/PgClass.h"
#include <QSplitter>
#include <memory>
#include <optional>
class PgLabTableView;
class SqlCodePreview;
class PgDatabaseCatalog;
class ColumnTableModel;
class QSortFilterProxyModel;
class QItemSelection;
class QAbstractItemModel;
class ColumnPage : public QSplitter
{
Q_OBJECT
public:
explicit ColumnPage(QWidget *parent = nullptr);
void setData(std::shared_ptr<const PgDatabaseCatalog> cat, const std::optional<PgClass> &cls);
//void setFilter(const std::optional<PgClass> &cls);
signals:
public slots:
private:
PgLabTableView *m_tableView = nullptr;
SqlCodePreview *m_definitionView = nullptr;
ColumnTableModel *m_columnModel = nullptr;
QSortFilterProxyModel *m_sortFilterProxy = nullptr;
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
std::optional<PgClass> m_Class;
private slots:
void tableView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
};
#endif // COLUMNPAGE_H

View file

@ -0,0 +1,55 @@
#include "catalog/widgets/DependantsPage.h"
#include "ResultTableModelUtil.h"
#include "UserConfiguration.h"
#include "catalog/PgClass.h"
#include "catalog/models/DependantsTableModel.h"
#include "CustomFilterSortModel.h"
#include "CustomDataRole.h"
#include "util/PgLabTableView.h"
#include <QStringBuilder>
#include <unordered_set>
DependantsPage::DependantsPage(QWidget *parent)
: CatalogPageBase(parent)
{
m_model = new DependantsTableModel(this);
m_sortFilterProxy->setSourceModel(m_model);
// connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
// this, &DependentsPage::tableView_selectionChanged);
// connect(m_model, &DependentsTableModel::modelReset, m_definitionView, &SqlCodePreview::clear);
}
void DependantsPage::catalogSet()
{
m_model->setCatalog(m_catalog);
}
void DependantsPage::setFilter(const std::optional<PgClass> &cls)
{
m_model->loadForTable(cls ? cls->oid() : InvalidOid);
m_tableView->resizeColumnsToContents();
}
//void DependentsPage::tableView_selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
//{
// auto rijen = selectedRows();
// QString drops;
// QString creates;
// for (auto rij : rijen) {
// auto&& t = m_model->trigger(rij);
// drops += t.dropSql() % "\n";
// creates += t.createSql() % "\n";
// const PgProc *proc = m_catalog->procs()->getByKey(t.foid);
// if (proc) {
// creates += "\n" % proc->createSql() % "\n";
// }
// }
// m_definitionView->setPlainText(drops % "\n" % creates);
//}

View file

@ -0,0 +1,30 @@
#ifndef DEPENDENTSPAGE_H
#define DEPENDENTSPAGE_H
#include "catalog/widgets/CatalogPageBase.h"
class PgClass;
class DependantsTableModel;
class QItemSelection;
class DependantsPage : public CatalogPageBase {
Q_OBJECT
public:
explicit DependantsPage(QWidget *parent = nullptr);
void setFilter(const std::optional<PgClass> &cls);
signals:
public slots:
protected:
void catalogSet() override;
private:
DependantsTableModel *m_model = nullptr;
private slots:
// void tableView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
};
#endif // DEPENDENTSPAGE_H

View file

@ -0,0 +1,57 @@
#include "TriggerPage.h"
#include "ResultTableModelUtil.h"
#include "UserConfiguration.h"
#include "catalog/PgClass.h"
#include "SqlCodePreview.h"
#include "catalog/models/TriggerTableModel.h"
#include "CustomFilterSortModel.h"
#include "CustomDataRole.h"
#include "util/PgLabTableView.h"
#include "catalog/PgProcContainer.h"
#include <QHeaderView>
#include <QStringBuilder>
#include <unordered_set>
TriggerPage::TriggerPage(QWidget *parent)
: CatalogPageBase(parent)
{
m_model = new TriggerTableModel(this);
m_sortFilterProxy->setSourceModel(m_model);
connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &TriggerPage::tableView_selectionChanged);
connect(m_model, &TriggerTableModel::modelReset, m_definitionView, &SqlCodePreview::clear);
}
void TriggerPage::catalogSet()
{
m_model->setCatalog(m_catalog);
}
void TriggerPage::setFilter(const std::optional<PgClass> &cls)
{
m_sortFilterProxy->setOidFilterTable(cls ? cls->oid() : InvalidOid, FirstHiddenValue);
m_tableView->resizeColumnsToContents();
}
void TriggerPage::tableView_selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
{
auto rijen = selectedRows();
QString drops;
QString creates;
for (auto rij : rijen) {
auto&& t = m_model->trigger(rij);
drops += t.dropSql() % "\n";
creates += t.createSql() % "\n";
const PgProc *proc = m_catalog->procs()->getByKey(t.foid);
if (proc) {
creates += "\n" % proc->createSql() % "\n";
}
}
m_definitionView->setPlainText(drops % "\n" % creates);
}

View file

@ -0,0 +1,30 @@
#ifndef TRIGGERPAGE_H
#define TRIGGERPAGE_H
#include "catalog/widgets/CatalogPageBase.h"
class PgClass;
class TriggerTableModel;
class QItemSelection;
class TriggerPage : public CatalogPageBase {
Q_OBJECT
public:
explicit TriggerPage(QWidget *parent = nullptr);
// TriggerPage(QWidget *parent = nullptr);
void setFilter(const std::optional<PgClass> &cls);
signals:
public slots:
protected:
void catalogSet() override;
private:
TriggerTableModel *m_model = nullptr;
private slots:
void tableView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
};
#endif // TRIGGERPAGE_H