From dbdc7bd965b6ab0e6e48afcba708198e2b8f78f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20=C3=81ngel=20San=20Mart=C3=ADn?= Date: Thu, 14 Jan 2021 09:10:58 +0100 Subject: [PATCH] Add a class for processing search queries and create the comics model data --- YACReaderLibrary/YACReaderLibrary.pro | 2 + .../db/comic_query_result_procesor.cpp | 112 ++++++++++++++++++ .../db/comic_query_result_procesor.h | 32 +++++ 3 files changed, 146 insertions(+) create mode 100644 YACReaderLibrary/db/comic_query_result_procesor.cpp create mode 100644 YACReaderLibrary/db/comic_query_result_procesor.h diff --git a/YACReaderLibrary/YACReaderLibrary.pro b/YACReaderLibrary/YACReaderLibrary.pro index 6a81ad51..4162cb36 100644 --- a/YACReaderLibrary/YACReaderLibrary.pro +++ b/YACReaderLibrary/YACReaderLibrary.pro @@ -78,6 +78,7 @@ QT += sql network widgets script HEADERS += comic_flow.h \ ../common/concurrent_queue.h \ create_library_dialog.h \ + db/comic_query_result_procesor.h \ db/query_lexer.h \ library_creator.h \ library_window.h \ @@ -154,6 +155,7 @@ HEADERS += comic_flow.h \ SOURCES += comic_flow.cpp \ create_library_dialog.cpp \ + db/comic_query_result_procesor.cpp \ db/query_lexer.cpp \ library_creator.cpp \ library_window.cpp \ diff --git a/YACReaderLibrary/db/comic_query_result_procesor.cpp b/YACReaderLibrary/db/comic_query_result_procesor.cpp new file mode 100644 index 00000000..270075aa --- /dev/null +++ b/YACReaderLibrary/db/comic_query_result_procesor.cpp @@ -0,0 +1,112 @@ +#include "comic_query_result_procesor.h" + +#include "comic_item.h" +#include "comic_model.h" +#include "data_base_management.h" +#include "qnaturalsorting.h" +#include "db_helper.h" +#include "query_parser.h" + +#include "QsLog.h" + +QString getLastExecutedQuery(const QSqlQuery &query) +{ + QString str = query.lastQuery(); + QMapIterator it(query.boundValues()); + while (it.hasNext()) { + it.next(); + str.replace(it.key(), it.value().toString()); + } + return str; +} + +YACReader::ComicQueryResultProcesor::ComicQueryResultProcesor() + : querySearchQueue(1) +{ +} + +void YACReader::ComicQueryResultProcesor::createModelData(const YACReader::SearchModifiers modifier, const QString &filter, const QString &databasePath) +{ + querySearchQueue.cancellPending(); + + querySearchQueue.enqueue([=] { + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); + QSqlQuery selectQuery(db); + + std::string queryString("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " + "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) LEFT JOIN folder f ON (f.id == c.parentId) WHERE "); + + try { + QueryParser parser; + auto result = parser.parse(filter.toStdString()); + result.buildSqlString(queryString); + + switch (modifier) { + case YACReader::NoModifiers: + queryString += " LIMIT :limit"; + break; + + case YACReader::OnlyRead: + queryString += " AND ci.read = 1 LIMIT :limit"; + break; + + case YACReader::OnlyUnread: + queryString += " AND ci.read = 0 LIMIT :limit"; + break; + + default: + queryString += " LIMIT :limit"; + QLOG_ERROR() << "not implemented"; + break; + } + selectQuery.prepare(queryString.c_str()); + selectQuery.bindValue(":limit", 500); //TODO, load this value from settings + result.bindValues(selectQuery); + + selectQuery.exec(); + + auto data = modelData(selectQuery); + + emit newData(data, databasePath); + } catch (const std::exception &e) { + //Do nothing, uncomplete search string will end here and it is part of how the QueryParser works + //I don't like the idea of using exceptions for this though + } + + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); + }); +} + +QList *YACReader::ComicQueryResultProcesor::modelData(QSqlQuery &sqlquery) +{ + auto list = new QList(); + + int numColumns = sqlquery.record().count(); + + while (sqlquery.next()) { + QList data; + + for (int i = 0; i < numColumns; i++) + data << sqlquery.value(i); + + list->append(new ComicItem(data)); + } + + std::sort(list->begin(), list->end(), [](const ComicItem *c1, const ComicItem *c2) { + if (c1->data(ComicModel::Number).isNull() && c2->data(ComicModel::Number).isNull()) { + return naturalSortLessThanCI(c1->data(ComicModel::FileName).toString(), c2->data(ComicModel::FileName).toString()); + } else { + if (c1->data(ComicModel::Number).isNull() == false && c2->data(ComicModel::Number).isNull() == false) { + return c1->data(ComicModel::Number).toInt() < c2->data(ComicModel::Number).toInt(); + } else { + return c2->data(ComicModel::Number).isNull(); + } + } + }); + + return list; +} diff --git a/YACReaderLibrary/db/comic_query_result_procesor.h b/YACReaderLibrary/db/comic_query_result_procesor.h new file mode 100644 index 00000000..ba71da99 --- /dev/null +++ b/YACReaderLibrary/db/comic_query_result_procesor.h @@ -0,0 +1,32 @@ +#ifndef COMIC_QUERY_RESULT_PROCESOR_H +#define COMIC_QUERY_RESULT_PROCESOR_H + +#include +#include + +#include "yacreader_global_gui.h" +#include "concurrent_queue.h" + +class ComicItem; + +namespace YACReader { + +class ComicQueryResultProcesor : public QObject +{ + Q_OBJECT +public: + ComicQueryResultProcesor(); + +public slots: + void createModelData(const SearchModifiers modifier, const QString &filter, const QString &databasePath); +signals: + void newData(QList *, const QString &); + +private: + ConcurrentQueue querySearchQueue; + + QList *modelData(QSqlQuery &sqlquery); +}; +}; + +#endif // COMIC_QUERY_RESULT_PROCESOR_H