Added page with the types (no details yet)

This commit is contained in:
eelke 2021-04-01 14:58:42 +02:00
parent bdef76ed8a
commit 4c175d8c2c
16 changed files with 418 additions and 11 deletions

View file

@ -22,7 +22,7 @@ QVariant BaseTableModel::data(const QModelIndex &index, int role) const
return v; return v;
} }
QVariant BaseTableModel::getDataMeaning(const QModelIndex &index) const QVariant BaseTableModel::getDataMeaning(const QModelIndex &) const
{ {
return static_cast<int>(DataMeaningNormal); return static_cast<int>(DataMeaningNormal);
} }

View file

@ -5,6 +5,7 @@
#include "widgets/CatalogNamespacePage.h" #include "widgets/CatalogNamespacePage.h"
#include "widgets/CatalogSequencesPage.h" #include "widgets/CatalogSequencesPage.h"
#include "widgets/CatalogTablesPage.h" #include "widgets/CatalogTablesPage.h"
#include "widgets/CatalogTypesPage.h"
#include <QApplication> #include <QApplication>
#include <QTabWidget> #include <QTabWidget>
@ -20,6 +21,7 @@ CatalogInspector::CatalogInspector(std::shared_ptr<OpenDatabase> open_database,
m_tablesPage = new CatalogTablesPage(this); m_tablesPage = new CatalogTablesPage(this);
m_functionsPage = new CatalogFunctionsPage(this); m_functionsPage = new CatalogFunctionsPage(this);
m_sequencesPage = new CatalogSequencesPage(this); m_sequencesPage = new CatalogSequencesPage(this);
m_typesPage = new CatalogTypesPage(this);
auto layout = new QVBoxLayout(this); auto layout = new QVBoxLayout(this);
setLayout(layout); setLayout(layout);
@ -28,6 +30,7 @@ CatalogInspector::CatalogInspector(std::shared_ptr<OpenDatabase> open_database,
m_tabWidget->addTab(m_tablesPage, ""); m_tabWidget->addTab(m_tablesPage, "");
m_tabWidget->addTab(m_functionsPage, ""); m_tabWidget->addTab(m_functionsPage, "");
m_tabWidget->addTab(m_sequencesPage, ""); m_tabWidget->addTab(m_sequencesPage, "");
m_tabWidget->addTab(m_typesPage, "");
setCatalog(open_database->catalog()); setCatalog(open_database->catalog());
retranslateUi(false); retranslateUi(false);
@ -45,6 +48,8 @@ void CatalogInspector::retranslateUi(bool all)
QApplication::translate("CatalogInspector", "Functions", nullptr)); QApplication::translate("CatalogInspector", "Functions", nullptr));
m_tabWidget->setTabText(m_tabWidget->indexOf(m_sequencesPage), m_tabWidget->setTabText(m_tabWidget->indexOf(m_sequencesPage),
QApplication::translate("CatalogInspector", "Sequences", nullptr)); QApplication::translate("CatalogInspector", "Sequences", nullptr));
m_tabWidget->setTabText(m_tabWidget->indexOf(m_typesPage),
QApplication::translate("CatalogInspector", "Types", nullptr));
} }
CatalogInspector::~CatalogInspector() CatalogInspector::~CatalogInspector()
@ -58,6 +63,7 @@ void CatalogInspector::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
m_tablesPage->setCatalog(cat); m_tablesPage->setCatalog(cat);
m_functionsPage->setCatalog(cat); m_functionsPage->setCatalog(cat);
m_sequencesPage->setCatalog(cat); m_sequencesPage->setCatalog(cat);
m_typesPage->setCatalog(cat);
} }
void CatalogInspector::setNamespaceFilter(NamespaceFilter filter) void CatalogInspector::setNamespaceFilter(NamespaceFilter filter)

View file

@ -9,6 +9,7 @@ class CatalogFunctionsPage;
class CatalogSequencesPage; class CatalogSequencesPage;
class CatalogTablesPage; class CatalogTablesPage;
class CatalogNamespacePage; class CatalogNamespacePage;
class CatalogTypesPage;
class OpenDatabase; class OpenDatabase;
class PgDatabaseCatalog; class PgDatabaseCatalog;
class QTabWidget; class QTabWidget;
@ -29,6 +30,7 @@ private:
CatalogTablesPage *m_tablesPage = nullptr; CatalogTablesPage *m_tablesPage = nullptr;
CatalogFunctionsPage *m_functionsPage = nullptr; CatalogFunctionsPage *m_functionsPage = nullptr;
CatalogSequencesPage *m_sequencesPage = nullptr; CatalogSequencesPage *m_sequencesPage = nullptr;
CatalogTypesPage *m_typesPage = nullptr;
std::shared_ptr<PgDatabaseCatalog> m_catalog; std::shared_ptr<PgDatabaseCatalog> m_catalog;
void retranslateUi(bool all = true); void retranslateUi(bool all = true);

View file

@ -29,7 +29,7 @@ ColumnPage::ColumnPage(QWidget *parent)
m_tableView->setItemDelegateForColumn(ColumnTableModel::TypeCol, new QStyledItemDelegate(this)); m_tableView->setItemDelegateForColumn(ColumnTableModel::TypeCol, new QStyledItemDelegate(this));
m_tableView->setModel(m_sortFilterProxy); m_tableView->setModel(m_sortFilterProxy);
m_tableView->setSortingEnabled(true); m_tableView->setSortingEnabled(true);
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows); // m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
m_sortFilterProxy->sort(ColumnTableModel::AttnumCol, Qt::AscendingOrder); m_sortFilterProxy->sort(ColumnTableModel::AttnumCol, Qt::AscendingOrder);
connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged, connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged,

View file

@ -104,7 +104,7 @@ void PropertyProxyModel::setActiveRow(const QModelIndex &row)
QVector<int>() << Qt::DisplayRole); QVector<int>() << Qt::DisplayRole);
} }
Qt::ItemFlags PropertyProxyModel::flags(const QModelIndex &index) const Qt::ItemFlags PropertyProxyModel::flags(const QModelIndex &) const
{ {
return Qt::ItemIsSelectable | Qt::ItemIsEnabled; return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
} }

View file

@ -141,7 +141,6 @@ QVariant RolesTableModel::getData(const QModelIndex &index) const
v = authid.bypassRls; v = authid.bypassRls;
break; break;
case ConnlimitCol: case ConnlimitCol:
// todo lookup tablespace name
v = authid.connLimit; v = authid.connLimit;
break; break;
case ValidUntilCol: case ValidUntilCol:

101
pglab/TypeModel.cpp Normal file
View file

@ -0,0 +1,101 @@
#include "TypeModel.h"
#include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgNamespace.h"
#include "catalog/PgTypeContainer.h"
TypeModel::TypeModel(QObject * parent)
: QAbstractTableModel(parent)
{
}
QVariant TypeModel::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");
}
}
}
return {};
}
void TypeModel::setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat)
{
if (cat != m_catalog) {
m_catalog = cat;
refreshConnection = connect(m_catalog.get(), &PgDatabaseCatalog::refreshed,
this, &TypeModel::refresh);
}
refresh();
}
//void TypeModel::setNamespaceFilter(NamespaceFilter filter)
//{
// m_namespaceFilter = filter;
// refresh();
//}
void TypeModel::refresh()
{
if (!m_catalog)
return;
beginResetModel();
auto && typs = m_catalog->types();
m_types.clear();
for (auto&& s : *typs) {
// 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_types.push_back(s);
}
endResetModel();
}
PgType TypeModel::typ(int row) const
{
return m_types.at(static_cast<size_t>(row));
}
int TypeModel::rowCount(const QModelIndex &) const
{
return static_cast<int>(m_types.size());
}
int TypeModel::columnCount(const QModelIndex &) const
{
return colCount;
}
QVariant TypeModel::data(const QModelIndex &index, int role) const
{
if (m_types.empty())
return {};
int row = index.row();
auto && seq = m_types.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();
}
}
return {};
}

40
pglab/TypeModel.h Normal file
View file

@ -0,0 +1,40 @@
#ifndef TYPEMODEL_H
#define TYPEMODEL_H
#include <QAbstractTableModel>
#include "catalog/PgType.h"
class TypeModel : public QAbstractTableModel
{
Q_OBJECT
public:
enum e_Columns : int {
NameCol,
SchemaCol,
OwnerCol,
colCount
};
TypeModel(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;
PgType typ(int row) const;
private:
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
std::vector<PgType> m_types;
//NamespaceFilter m_namespaceFilter = NamespaceFilter::User;
QMetaObject::Connection refreshConnection;
void refresh();
};
#endif

View file

@ -87,7 +87,8 @@ PropertyProxyModel.cpp \
widgets/CatalogConstraintPage.cpp \ widgets/CatalogConstraintPage.cpp \
widgets/CatalogTablesPage.cpp \ widgets/CatalogTablesPage.cpp \
widgets/CatalogFunctionsPage.cpp \ widgets/CatalogFunctionsPage.cpp \
widgets/CatalogSequencesPage.cpp widgets/CatalogSequencesPage.cpp \
widgets/CatalogTypesPage.cpp
HEADERS += \ HEADERS += \
ConnectionConfigurationWidget.h \ ConnectionConfigurationWidget.h \
@ -160,7 +161,8 @@ CustomDataRole.h \
widgets/CatalogTablesPage.h \ widgets/CatalogTablesPage.h \
widgets/CatalogFunctionsPage.h \ widgets/CatalogFunctionsPage.h \
widgets/CatalogSequencesPage.h \ widgets/CatalogSequencesPage.h \
NamespaceFilter.h NamespaceFilter.h \
widgets/CatalogTypesPage.h
FORMS += \ FORMS += \
ConnectionManagerWindow.ui \ ConnectionManagerWindow.ui \

View file

@ -0,0 +1,78 @@
#include "CatalogTypesPage.h"
#include "ResultTableModelUtil.h"
#include "CustomFilterSortModel.h"
#include "CustomDataRole.h"
#include "PgLabItemDelegate.h"
#include "catalog/PgType.h"
#include "model/TypeSelectionItemModel.h"
#include "SqlCodePreview.h"
#include "PgLabTableView.h"
#include <optional>
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->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

@ -12,7 +12,10 @@ void operator<<(TypCategory &s, const Pgsql::Value &v)
case 'B': case 'B':
s = TypCategory::Boolean; s = TypCategory::Boolean;
break; break;
case 'D': case 'C':
s = TypCategory::Composite;
break;
case 'D':
s = TypCategory::DateTime; s = TypCategory::DateTime;
break; break;
case 'E': case 'E':

View file

@ -1,4 +1,5 @@
#include "TypeSelectionItemModel.h" #include "TypeSelectionItemModel.h"
//#include "CustomDataRole.h"
#include "catalog/PgTypeContainer.h" #include "catalog/PgTypeContainer.h"
#include <algorithm> #include <algorithm>
@ -56,7 +57,7 @@ void TypeSelectionItemModel::setTypeList(std::shared_ptr<const PgTypeContainer>
std::sort(m_types.begin(), m_types.end()); std::sort(m_types.begin(), m_types.end());
} }
//emit dataChanged(this->createIndex(0, 0), this->createIndex(types->count(), 0), QVector<int>() << Qt::DisplayRole); //emit dataChanged(this->createIndex(0, 0), this->createIndex(types->count(), 0), QVector<int>() << Qt::DisplayRole);
endResetModel(); endResetModel();
} }
// ---------------- // ----------------
@ -82,6 +83,9 @@ int TypeModel::columnCount(const QModelIndex &/*parent*/) const
QVariant TypeModel::data(const QModelIndex &index, int role) const QVariant TypeModel::data(const QModelIndex &index, int role) const
{ {
// if (role == CustomDataTypeRole)
// return getType(index.column());
if (index.isValid()) { if (index.isValid()) {
int row = index.row(); int row = index.row();
int column = index.column(); int column = index.column();
@ -91,15 +95,90 @@ QVariant TypeModel::data(const QModelIndex &index, int role) const
switch (column) { switch (column) {
case OidCol: return elem.oid(); case OidCol: return elem.oid();
case NameCol: return elem.objectName(); case NameCol: return elem.objectName();
case NamespaceCol: return elem.nsName();
case OwnerCol: return elem.ownerName();
case CategoryCol: return TypCategoryString(elem.category);
} }
} }
} }
return QVariant(); return QVariant();
}
QString TypeModel::TypCategoryString(TypCategory tc)
{
switch (tc) {
case TypCategory::Array:
return tr("array");
case TypCategory::Boolean:
return tr("boolean");
case TypCategory::Composite:
return tr("composite");
case TypCategory::DateTime:
return tr("datetime");
case TypCategory::Enum:
return tr("enum");
case TypCategory::Geometric:
return tr("geometric");
case TypCategory::NetworkAddress:
return tr("networkaddress");
case TypCategory::Numeric:
return tr("numeric");
case TypCategory::Pseudo:
return tr("pseude");
case TypCategory::Range:
return tr("range");
case TypCategory::String:
return tr("string");
case TypCategory::Timespan:
return tr("timespan");
case TypCategory::UserDefined:
return tr("user");
case TypCategory::BitString:
return tr("bitstring");
case TypCategory::Unknown:
return tr("unknown");
}
return "?";
}
Oid TypeModel::getType(int column) const
{
switch (column) {
case OidCol:
return Pgsql::oid_oid;
case NameCol:
case NamespaceCol:
case OwnerCol:
case CategoryCol:
return Pgsql::varchar_oid;
}
return InvalidOid;
} }
void TypeModel::setTypeList(std::shared_ptr<const PgTypeContainer> types) void TypeModel::setTypeList(std::shared_ptr<const PgTypeContainer> types)
{ {
beginResetModel(); beginResetModel();
m_types = types; m_types = types;
endResetModel(); endResetModel();
}
PgType TypeModel::typ(int row) const
{
return m_types->getByIdx(row);
}
QVariant TypeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
switch (section) {
case OidCol: return tr("Oid");
case NameCol: return tr("Name");
case NamespaceCol: return tr("Schema");
case OwnerCol: return tr("Owner");
case CategoryCol: return tr("Category");
}
}
}
return {};
} }

View file

@ -4,6 +4,7 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "catalog/PgType.h"
class PgTypeContainer; class PgTypeContainer;
@ -28,19 +29,27 @@ public:
enum e_Columns : int { enum e_Columns : int {
OidCol, OidCol,
NameCol, // NameCol, //
NamespaceCol,
OwnerCol,
CategoryCol,
colCount colCount
}; };
explicit TypeModel(QObject *parent = 0); explicit TypeModel(QObject *parent = 0);
void setTypeList(std::shared_ptr<const PgTypeContainer> types); void setTypeList(std::shared_ptr<const PgTypeContainer> types);
PgType typ(int row) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(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; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
private: private:
std::shared_ptr<const PgTypeContainer> m_types; std::shared_ptr<const PgTypeContainer> m_types;
static QString TypCategoryString(TypCategory tc);
Oid getType(int column) const;
}; };

View file

@ -211,6 +211,48 @@ QString ConvertToMultiLineRawCppString(const QString &in)
return out; return out;
} }
namespace {
class Token {
public:
enum Type {
Code,
StringLiteral,
SingleLineComment,
MultiLineComment
};
const Type type;
/// Depends on type
/// Code: literal copy of the matched code
/// StringLiteral: the contents of the string literal, escapes have been unescaped
/// *Comment, the text in the comment
const QString data;
Token(Type type, QString data)
: type(type)
, data(data)
{}
};
/// Tokenizer to get SQL out of a piece of programming language code
///
/// It works by ignoring most input and only get's triggered by string literals
/// and comments. It does return tokens for the code in between just so
class ProgLangTokenizer {
public:
ProgLangTokenizer(const QString &in)
: input(in)
{}
private:
const QString input;
int position = 0;
};
}
QString ConvertLangToSqlString(const QString &in) QString ConvertLangToSqlString(const QString &in)
{ {
// Assume mostly C++ for now but allow some other things like // Assume mostly C++ for now but allow some other things like
@ -232,6 +274,7 @@ QString ConvertLangToSqlString(const QString &in)
WHITESPACE, WHITESPACE,
PREFIX, PREFIX,
IN_STRING, IN_STRING,
SingleLineComment,
END, END,
ERROR ERROR
} state = WHITESPACE; } state = WHITESPACE;

View file

@ -60,3 +60,14 @@ TEST(ConvertLangToSqlString, testSemiColon)
auto output = ConvertLangToSqlString(in); auto output = ConvertLangToSqlString(in);
ASSERT_EQ(output, expected); ASSERT_EQ(output, expected);
} }
TEST(ConvertLangToSqlString, testComment)
{
QString in(R"__( "SELECT * " // comment
"FROM t"; )__");
QString expected(R"__(SELECT *
FROM t)__");
auto output = ConvertLangToSqlString(in);
ASSERT_EQ(output, expected);
}