Use new Query class from outside SqliteTableModel to assemble queries

This commit is contained in:
Martin Kleusberg
2018-11-01 17:56:48 +01:00
parent ed06c0289e
commit f1e01dde8c
7 changed files with 84 additions and 97 deletions

View File

@@ -230,7 +230,7 @@ QMimeData* DbStructureModel::mimeData(const QModelIndexList& indices) const
SqliteTableModel tableModel(m_db);
sqlb::ObjectIdentifier objid(data(index.sibling(index.row(), ColumnSchema), Qt::DisplayRole).toString(),
data(index.sibling(index.row(), ColumnName), Qt::DisplayRole).toString());
tableModel.setTable(objid);
tableModel.setQuery(sqlb::Query(objid));
if(tableModel.completeCache())
{
// Only continue if all data was fetched

View File

@@ -80,21 +80,21 @@ QDataStream& operator>>(QDataStream& ds, sqlb::ObjectIdentifier& objid)
// These are temporary helper functions to turn a vector of sorted columns into a single column to sort and vice verse. This is done by just taking the
// first sort column there is and ignoring all the others or creating a single item vector respectively. These functions can be removed once all parts
// of the application have been converted to deal with vectors of sorted columns.
void fromSortOrderVector(const QVector<BrowseDataTableSettings::SortedColumn>& vector, int& index, Qt::SortOrder& mode)
static void fromSortOrderVector(const std::vector<sqlb::SortedColumn>& vector, int& index, Qt::SortOrder& mode)
{
if(vector.size())
{
index = vector.at(0).index;
mode = vector.at(0).mode;
index = vector.at(0).column;
mode = vector.at(0).direction == sqlb::Ascending ? Qt::AscendingOrder : Qt::DescendingOrder;
} else {
index = 0;
mode = Qt::AscendingOrder;
}
}
QVector<BrowseDataTableSettings::SortedColumn> toSortOrderVector(int index, Qt::SortOrder mode)
static std::vector<sqlb::SortedColumn> toSortOrderVector(int index, Qt::SortOrder mode)
{
QVector<BrowseDataTableSettings::SortedColumn> vector;
vector.push_back(BrowseDataTableSettings::SortedColumn(index, mode));
std::vector<sqlb::SortedColumn> vector;
vector.emplace_back(index, mode == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending);
return vector;
}
@@ -625,7 +625,7 @@ void MainWindow::populateTable()
// No stored settings found.
// Set table name and apply default display format settings
m_browseTableModel->setTable(tablename, 0, Qt::AscendingOrder);
m_browseTableModel->setQuery(sqlb::Query(tablename));
// There aren't any information stored for this table yet, so use some default values
@@ -655,10 +655,21 @@ void MainWindow::populateTable()
// The filters can be left empty as they are
} else {
// Stored settings found. Retrieve them.
// Stored settings found. Retrieve them and assemble a query from them.
BrowseDataTableSettings storedData = browseTableSettings[tablename];
sqlb::Query query(tablename);
// Load display formats and set them along with the table name
// Sorting
int sortOrderIndex;
Qt::SortOrder sortOrderMode;
fromSortOrderVector(storedData.query.orderBy(), sortOrderIndex, sortOrderMode);
query.orderBy().emplace_back(sortOrderIndex, sortOrderMode == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending);
// Filters
for(auto it=storedData.filterValues.constBegin();it!=storedData.filterValues.constEnd();++it)
query.where().insert({it.key(), CondFormat::filterToSqlCondition(it.value(), m_browseTableModel->encoding()).toStdString()});
// Display formats
QVector<QString> v;
bool only_defaults = true;
if(db.getObjectByName(tablename))
@@ -669,21 +680,18 @@ void MainWindow::populateTable()
QString format = storedData.displayFormats[i+1];
if(format.size())
{
v.push_back(format);
query.selectedColumns().emplace_back(tablefields.at(i).name.toStdString(), format.toStdString());
only_defaults = false;
} else {
v.push_back(sqlb::escapeIdentifier(tablefields.at(i).name));
query.selectedColumns().emplace_back(tablefields.at(i).name.toStdString(), tablefields.at(i).name.toStdString());
}
}
}
int sortOrderIndex;
Qt::SortOrder sortOrderMode;
fromSortOrderVector(storedData.sortOrder, sortOrderIndex, sortOrderMode);
if(only_defaults)
m_browseTableModel->setTable(tablename, sortOrderIndex, sortOrderMode, storedData.filterValues);
else
m_browseTableModel->setTable(tablename, sortOrderIndex, sortOrderMode, storedData.filterValues, v);
query.selectedColumns().clear();
// Apply query
m_browseTableModel->setQuery(query);
// There is information stored for this table, so extract it and apply it
applyBrowseTableSettings(storedData);
@@ -737,7 +745,7 @@ void MainWindow::applyBrowseTableSettings(BrowseDataTableSettings storedData, bo
// Sorting
int sortOrderIndex;
Qt::SortOrder sortOrderMode;
fromSortOrderVector(storedData.sortOrder, sortOrderIndex, sortOrderMode);
fromSortOrderVector(storedData.query.orderBy(), sortOrderIndex, sortOrderMode);
ui->dataTable->filterHeader()->setSortIndicator(sortOrderIndex, sortOrderMode);
// Filters
@@ -1984,9 +1992,9 @@ void MainWindow::browseTableHeaderClicked(int logicalindex)
BrowseDataTableSettings& settings = browseTableSettings[currentlyBrowsedTableName()];
int dummy;
Qt::SortOrder order;
fromSortOrderVector(settings.sortOrder, dummy, order);
fromSortOrderVector(settings.query.orderBy(), dummy, order);
order = order == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
settings.sortOrder = toSortOrderVector(logicalindex, order);
settings.query.orderBy() = toSortOrderVector(logicalindex, order);
ui->dataTable->sortByColumn(logicalindex, order);
// select the first item in the column so the header is bold
@@ -2466,7 +2474,7 @@ static void loadBrowseDataTableSettings(BrowseDataTableSettings& settings, QXmlS
{
int sortOrderIndex = xml.attributes().value("sort_order_index").toInt();
Qt::SortOrder sortOrderMode = static_cast<Qt::SortOrder>(xml.attributes().value("sort_order_mode").toInt());
settings.sortOrder = toSortOrderVector(sortOrderIndex, sortOrderMode);
settings.query.orderBy() = toSortOrderVector(sortOrderIndex, sortOrderMode);
}
settings.showRowid = xml.attributes().value("show_row_id").toInt();
@@ -2483,7 +2491,7 @@ static void loadBrowseDataTableSettings(BrowseDataTableSettings& settings, QXmlS
{
int index = xml.attributes().value("index").toInt();
int mode = xml.attributes().value("mode").toInt();
settings.sortOrder.push_back(BrowseDataTableSettings::SortedColumn(index, mode));
settings.query.orderBy().emplace_back(index, mode == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending);
xml.skipCurrentElement();
}
}
@@ -2704,7 +2712,7 @@ bool MainWindow::loadProject(QString filename, bool readOnly)
int sortIndex;
Qt::SortOrder sortMode;
fromSortOrderVector(browseTableSettings[current_table].sortOrder, sortIndex, sortMode);
fromSortOrderVector(browseTableSettings[current_table].query.orderBy(), sortIndex, sortMode);
ui->dataTable->sortByColumn(sortIndex, sortMode);
showRowidColumn(browseTableSettings[current_table].showRowid);
unlockViewEditing(!browseTableSettings[current_table].unlockViewPk.isEmpty(), browseTableSettings[current_table].unlockViewPk);
@@ -2767,11 +2775,11 @@ static void saveBrowseDataTableSettings(const BrowseDataTableSettings& object, Q
xml.writeAttribute("unlock_view_pk", object.unlockViewPk);
xml.writeStartElement("sort");
for(const auto& column : object.sortOrder)
for(const auto& column : object.query.orderBy())
{
xml.writeStartElement("column");
xml.writeAttribute("index", QString::number(column.index));
xml.writeAttribute("mode", QString::number(column.mode));
xml.writeAttribute("index", QString::number(column.column));
xml.writeAttribute("mode", QString::number(column.direction));
xml.writeEndElement();
}
xml.writeEndElement();

View File

@@ -5,6 +5,7 @@
#include "PlotDock.h"
#include "Palette.h"
#include "CondFormat.h"
#include "sql/Query.h"
#include <QMainWindow>
#include <QMap>
@@ -28,25 +29,7 @@ class MainWindow;
struct BrowseDataTableSettings
{
struct SortedColumn
{
SortedColumn() :
index(0),
mode(Qt::AscendingOrder)
{}
SortedColumn(int index_, Qt::SortOrder mode_) :
index(index_),
mode(mode_)
{}
SortedColumn(int index_, int mode_) :
index(index_),
mode(static_cast<Qt::SortOrder>(mode_))
{}
int index;
Qt::SortOrder mode;
};
QVector<SortedColumn> sortOrder;
sqlb::Query query; // NOTE: We only store the sort order in here (for now)
QMap<int, int> columnWidths;
QMap<int, QString> filterValues;
QMap<int, QVector<CondFormat>> condFormats;
@@ -68,7 +51,7 @@ struct BrowseDataTableSettings
int sortOrderIndex, sortOrderMode;
stream >> sortOrderIndex;
stream >> sortOrderMode;
object.sortOrder.push_back(SortedColumn(sortOrderIndex, sortOrderMode));
object.query.orderBy().emplace_back(sortOrderIndex, sortOrderMode == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending);
stream >> object.columnWidths;
stream >> object.filterValues;
stream >> object.displayFormats;

View File

@@ -47,15 +47,15 @@ std::string Query::buildQuery(bool withRowid) const
for(auto i=m_where.cbegin();i!=m_where.cend();++i)
{
const auto it = findSelectedColumnByName(i->first);
std::string column = sqlb::escapeIdentifier(i->first);
const auto it = findSelectedColumnByName(m_column_names.at(i->first));
std::string column = sqlb::escapeIdentifier(m_column_names.at(i->first));
if(it != m_selected_columns.cend() && it->selector != column)
column = it->selector;
where += column + " " + i->second + " AND ";
}
// Remove last 'AND '
where.erase(where.size() - 4);
// Remove last ' AND '
where.erase(where.size() - 5);
}
// Sorting
@@ -64,7 +64,8 @@ std::string Query::buildQuery(bool withRowid) const
{
order_by = "ORDER BY ";
for(const auto& sorted_column : m_sort)
order_by += sqlb::escapeIdentifier(sorted_column.column) + " " + sorted_column.direction + ",";
order_by += sqlb::escapeIdentifier(m_column_names.at(sorted_column.column)) + " "
+ (sorted_column.direction == sqlb::Ascending ? "ASC" : "DESC") + ",";
order_by.pop_back();
}

View File

@@ -10,15 +10,21 @@
namespace sqlb
{
enum SortDirection
{
Ascending,
Descending
};
struct SortedColumn
{
SortedColumn(const std::string& column_, const std::string& direction_) :
SortedColumn(int column_, SortDirection direction_) :
column(column_),
direction(direction_)
{}
std::string column;
std::string direction;
int column;
SortDirection direction;
};
struct SelectedColumn
@@ -43,6 +49,9 @@ public:
void clear();
std::string buildQuery(bool withRowid) const;
void setColumNames(const std::vector<std::string>& column_names) { m_column_names = column_names; }
std::vector<std::string> columnNames() const { return m_column_names; }
void setTable(const sqlb::ObjectIdentifier& table) { m_table = table; }
sqlb::ObjectIdentifier table() const { return m_table; }
@@ -52,17 +61,18 @@ public:
const std::vector<SelectedColumn>& selectedColumns() const { return m_selected_columns; }
std::vector<SelectedColumn>& selectedColumns() { return m_selected_columns; }
const std::unordered_map<std::string, std::string>& where() const { return m_where; }
std::unordered_map<std::string, std::string>& where() { return m_where; }
const std::unordered_map<int, std::string>& where() const { return m_where; }
std::unordered_map<int, std::string>& where() { return m_where; }
const std::vector<SortedColumn>& orderBy() const { return m_sort; }
std::vector<SortedColumn>& orderBy() { return m_sort; }
private:
std::vector<std::string> m_column_names;
sqlb::ObjectIdentifier m_table;
std::string m_rowid_column;
std::vector<SelectedColumn> m_selected_columns;
std::unordered_map<std::string, std::string> m_where;
std::unordered_map<int, std::string> m_where;
std::vector<SortedColumn> m_sort;
std::vector<SelectedColumn>::iterator findSelectedColumnByName(const std::string& name);

View File

@@ -112,22 +112,22 @@ void SqliteTableModel::setChunkSize(size_t chunksize)
m_chunkSize = chunksize;
}
void SqliteTableModel::setTable(const sqlb::ObjectIdentifier& table, int sortColumn, Qt::SortOrder sortOrder, const QMap<int, QString> filterValues, const QVector<QString>& display_format)
void SqliteTableModel::setQuery(const sqlb::Query& query)
{
// Unset all previous settings. When setting a table all information on the previously browsed data set is removed first.
reset();
// Save the table name
m_query.setTable(table);
// Save the query
m_query = query;
// The first column is the rowid column and therefore is always of type integer
m_vDataTypes.push_back(SQLITE_INTEGER);
// Get the data types of all other columns as well as the column names
bool allOk = false;
if(m_db.getObjectByName(table) && m_db.getObjectByName(table)->type() == sqlb::Object::Types::Table)
if(m_db.getObjectByName(query.table()) && m_db.getObjectByName(query.table())->type() == sqlb::Object::Types::Table)
{
sqlb::TablePtr t = m_db.getObjectByName<sqlb::Table>(table);
sqlb::TablePtr t = m_db.getObjectByName<sqlb::Table>(query.table());
if(t && t->fields.size()) // parsing was OK
{
QString rowid = t->rowidColumn();
@@ -157,34 +157,21 @@ void SqliteTableModel::setTable(const sqlb::ObjectIdentifier& table, int sortCol
// NOTE: It would be nice to eventually get rid of this piece here. As soon as the grammar parser is good enough...
if(!allOk)
{
QString sColumnQuery = QString::fromUtf8("SELECT * FROM %1;").arg(table.toString());
QString sColumnQuery = QString::fromUtf8("SELECT * FROM %1;").arg(query.table().toString());
m_query.setRowIdColumn("rowid");
m_headers.push_back("rowid");
m_headers.append(getColumns(nullptr, sColumnQuery, m_vDataTypes));
}
// Store filters and display formats
for(auto filterIt=filterValues.constBegin(); filterIt!=filterValues.constEnd(); ++filterIt)
updateFilter(filterIt.key(), filterIt.value(), false);
if(display_format.size())
{
for(int i=1;i<m_headers.size();i++)
{
QString format;
if(i <= display_format.size())
format = display_format[i-1];
else
format = m_headers[i];
// Tell the query object about the column names
std::vector<std::string> column_names;
for(const auto& h : m_headers)
column_names.push_back(h.toStdString());
//column_names.erase(column_names.begin(), column_names.begin()+1);
m_query.setColumNames(column_names);
m_query.selectedColumns().emplace_back(m_headers[i].toStdString(), format.toStdString());
}
}
// Set sort parameters. We're setting the sort columns to no sorting before calling sort() because this way, in sort() the
// current sort order is always changed and thus buildQuery() is always going to be called.
// This is also why we don't need to call buildQuery() here again.
m_query.orderBy().clear();
sort(sortColumn, sortOrder);
// Apply new query and update view
buildQuery();
}
void SqliteTableModel::setQuery(const QString& sQuery, bool dontClearHeaders)
@@ -465,7 +452,7 @@ Qt::ItemFlags SqliteTableModel::flags(const QModelIndex& index) const
void SqliteTableModel::sort(int column, Qt::SortOrder order)
{
// Don't do anything when the sort order hasn't changed
if(m_query.orderBy().size() && QString::fromStdString(m_query.orderBy().at(0).column) == m_headers.at(column) && m_query.orderBy().at(0).direction == (order == Qt::AscendingOrder ? "ASC" : "DESC"))
if(m_query.orderBy().size() && m_query.orderBy().at(0).column == column && m_query.orderBy().at(0).direction == (order == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending))
return;
// Reset sort order
@@ -473,7 +460,7 @@ void SqliteTableModel::sort(int column, Qt::SortOrder order)
// Save sort order
if (column >= 0 && column < m_headers.size())
m_query.orderBy().emplace_back(m_headers.at(column).toStdString(), (order == Qt::AscendingOrder ? "ASC" : "DESC"));
m_query.orderBy().emplace_back(column, (order == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending));
// Set the new query (but only if a table has already been set
if(!m_query.table().isEmpty())
@@ -706,20 +693,18 @@ void SqliteTableModel::setCondFormats(int column, const QVector<CondFormat>& con
emit layoutChanged();
}
void SqliteTableModel::updateFilter(int column, const QString& value, bool applyQuery)
void SqliteTableModel::updateFilter(int column, const QString& value)
{
QString whereClause = CondFormat::filterToSqlCondition(value, m_encoding);
// If the value was set to an empty string remove any filter for this column. Otherwise insert a new filter rule or replace the old one if there is already one
if(whereClause.isEmpty())
m_query.where().erase(m_headers.at(column).toStdString());
else {
m_query.where()[m_headers.at(column).toStdString()] = whereClause.toStdString();
}
m_query.where().erase(column);
else
m_query.where()[column] = whereClause.toStdString();
// Build the new query
if (applyQuery)
buildQuery();
buildQuery();
}
void SqliteTableModel::clearCache()

View File

@@ -84,7 +84,7 @@ public:
QString customQuery(bool withRowid) const { return QString::fromStdString(m_query.buildQuery(withRowid)); }
/// configure for browsing specified table
void setTable(const sqlb::ObjectIdentifier& table, int sortColumn = 0, Qt::SortOrder sortOrder = Qt::AscendingOrder, const QMap<int, QString> filterValues = QMap<int, QString>(), const QVector<QString> &display_format = QVector<QString>());
void setQuery(const sqlb::Query& query);
void setChunkSize(size_t chunksize);
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
@@ -115,7 +115,7 @@ public:
void setCondFormats(int column, const QVector<CondFormat>& condFormats);
public slots:
void updateFilter(int column, const QString& value, bool applyQuery = true);
void updateFilter(int column, const QString& value);
signals:
void finishedFetch(int fetched_row_begin, int fetched_row_end);