Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/extended search #36

Merged
merged 32 commits into from Jan 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d3de52c
Add commit 43aab01 of BenHanson/lexertl14 from github
iain-benson Nov 16, 2018
4a50d43
Add query parser class
iain-benson Nov 18, 2018
5fa7da1
Add folder into the query parser
iain-benson Nov 24, 2018
673ee1f
Use the query parser in the comic and folder model
iain-benson Nov 24, 2018
30529dc
Some small tidy ups
iain-benson Nov 24, 2018
9a66035
Add some documentation and attribution to the query parser
iain-benson Nov 24, 2018
7ccb338
Apply clang-format
luisangelsm Sep 23, 2019
2d3888b
Fix scopes
luisangelsm Sep 23, 2019
4990093
Remove c++17 dependency
luisangelsm Sep 23, 2019
8efb991
Use concatenation, rather than ostringstream
iain-benson Oct 24, 2019
255e51d
Fix binding values to search query
luisangelsm Jan 8, 2021
6438c92
Move query execution and model setup to the right scope
luisangelsm Jan 12, 2021
5037f3a
Fix data base removal in FolderModel
luisangelsm Jan 12, 2021
a777aa3
Replace lexertl with a custom lexeter implementation
luisangelsm Jan 12, 2021
ddb140d
Remove misplaced code
luisangelsm Jan 12, 2021
f09c595
Remove space and atWord tokens
luisangelsm Jan 14, 2021
260f538
Use an explicit constructor for TreeNode
luisangelsm Jan 14, 2021
7b36100
Use QString::fromStdString
luisangelsm Jan 14, 2021
fa5ce25
Add concurrent queue based on lambdas
luisangelsm Jan 14, 2021
dbdc7bd
Add a class for processing search queries and create the comics model…
luisangelsm Jan 14, 2021
ccc382d
Use ComicQueryResultProcesor
luisangelsm Jan 14, 2021
047fd24
Make the search line edit bigger
luisangelsm Jan 14, 2021
5343d24
Run folder search filtering in the background
luisangelsm Jan 14, 2021
c3b0780
Remove unused constant
luisangelsm Jan 14, 2021
dde60b7
YACReaderLibrary compiles using c++11 just fine
luisangelsm Jan 14, 2021
f803b54
Add support for boolean folder fields
luisangelsm Jan 14, 2021
f03ad84
Add support for `true` and `false` literals to be used with bool fields
luisangelsm Jan 14, 2021
82eb5c0
Add fallback for qt < 5.15
luisangelsm Jan 14, 2021
24c0a78
Remove reference to lexertl's license
luisangelsm Jan 14, 2021
6bb64c5
Import non-gui global header
luisangelsm Jan 14, 2021
76a307d
Remove comments
luisangelsm Jan 14, 2021
7e72c8b
Update CHANGELOG
luisangelsm Jan 14, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,8 @@ spanish only. Sorry for the mess.
Version counting is based on semantic versioning (Major.Feature.Patch)

## WIP
### YACReaderLibrary
* New search engine.

## 9.7.1
### YACReader
Expand Down
17 changes: 12 additions & 5 deletions YACReaderLibrary/YACReaderLibrary.pro
Expand Up @@ -14,6 +14,8 @@ INCLUDEPATH += . \

DEFINES += SERVER_RELEASE NOMINMAX YACREADER_LIBRARY

CONFIG += c++11

# load default build flags
include (../config.pri)
include (../dependencies/pdf_backend.pri)
Expand Down Expand Up @@ -67,10 +69,6 @@ macx {
QT += macextras gui-private
}

unix:!macx {
CONFIG += c++11
}

#CONFIG += release
CONFIG -= flat
QT += sql network widgets script
Expand All @@ -80,7 +78,11 @@ QT += sql network widgets script

# Input
HEADERS += comic_flow.h \
../common/concurrent_queue.h \
create_library_dialog.h \
db/comic_query_result_procesor.h \
db/folder_query_result_processor.h \
db/query_lexer.h \
library_creator.h \
library_window.h \
add_library_dialog.h \
Expand Down Expand Up @@ -147,6 +149,7 @@ HEADERS += comic_flow.h \
yacreader_comics_selection_helper.h \
yacreader_comic_info_helper.h \
db/reading_list.h \
db/query_parser.h \
current_comic_view_helper.h

!CONFIG(no_opengl) {
Expand All @@ -155,6 +158,9 @@ HEADERS += comic_flow.h \

SOURCES += comic_flow.cpp \
create_library_dialog.cpp \
db/comic_query_result_procesor.cpp \
db/folder_query_result_processor.cpp \
db/query_lexer.cpp \
library_creator.cpp \
library_window.cpp \
main.cpp \
Expand Down Expand Up @@ -219,7 +225,8 @@ SOURCES += comic_flow.cpp \
yacreader_comics_selection_helper.cpp \
yacreader_comic_info_helper.cpp\
db/reading_list.cpp \
current_comic_view_helper.cpp
current_comic_view_helper.cpp \
db/query_parser.cpp

!CONFIG(no_opengl) {
SOURCES += ../common/gl/yacreader_flow_gl.cpp
Expand Down
51 changes: 9 additions & 42 deletions YACReaderLibrary/db/comic_model.cpp
Expand Up @@ -9,6 +9,7 @@
#include "qnaturalsorting.h"
#include "comic_db.h"
#include "db_helper.h"
#include "query_parser.h"

//ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read
#include "QsLog.h"
Expand Down Expand Up @@ -595,59 +596,25 @@ void ComicModel::setupReadingModelData(const QString &databasePath)
endResetModel();
}

void ComicModel::setupModelData(const SearchModifiers modifier, const QString &filter, const QString &databasePath)
void ComicModel::setModelData(QList<ComicItem *> *data, const QString &databasePath)
{
beginResetModel();
qDeleteAll(_data);
_data.clear();
_databasePath = databasePath;
QString connectionName = "";

{
QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath);
QSqlQuery selectQuery(db);

switch (modifier) {
case YACReader::NoModifiers:
selectQuery.prepare("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) "
"WHERE UPPER(ci.title) LIKE UPPER(:filter) OR UPPER(c.fileName) LIKE UPPER(:filter) LIMIT :limit");
selectQuery.bindValue(":filter", "%%" + filter + "%%");
selectQuery.bindValue(":limit", 500); //TODO, load this value from settings
break;

case YACReader::OnlyRead:
selectQuery.prepare("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) "
"WHERE (UPPER(ci.title) LIKE UPPER(:filter) OR UPPER(c.fileName) LIKE UPPER(:filter)) AND ci.read = 1 LIMIT :limit");
selectQuery.bindValue(":filter", "%%" + filter + "%%");
selectQuery.bindValue(":limit", 500); //TODO, load this value from settings
break;
beginResetModel();

case YACReader::OnlyUnread:
selectQuery.prepare("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) "
"WHERE (UPPER(ci.title) LIKE UPPER(:filter) OR UPPER(c.fileName) LIKE UPPER(:filter)) AND ci.read = 0 LIMIT :limit");
selectQuery.bindValue(":filter", "%%" + filter + "%%");
selectQuery.bindValue(":limit", 500); //TODO, load this value from settings
break;
qDeleteAll(_data);

default:
QLOG_ERROR() << "not implemented";
break;
}
_data.clear();

selectQuery.exec();
QLOG_ERROR() << "-d2>" << data->size();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this line left here by mistake? It spams error messages every time the search edit's text changes to a non-empty value.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, my bad.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this line be removed or converted to QLOG_TRACE or QLOG_DEBUG?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed, I used that log to catch some issues while I was working on this PR but it doesn't have a purpose anymore.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in #194.


QLOG_DEBUG() << selectQuery.lastError() << "--";
_data.append(*data);

setupModelData(selectQuery);
connectionName = db.connectionName();
}
QSqlDatabase::removeDatabase(connectionName);
endResetModel();

emit searchNumResults(_data.length());

delete data;
}

QString ComicModel::getComicPath(QModelIndex mi)
Expand Down
6 changes: 2 additions & 4 deletions YACReaderLibrary/db/comic_model.h
Expand Up @@ -16,7 +16,6 @@ class ComicItem;

using namespace YACReader;

//! [0]
class ComicModel : public QAbstractItemModel
{
Q_OBJECT
Expand Down Expand Up @@ -89,8 +88,6 @@ class ComicModel : public QAbstractItemModel
void setupReadingListModelData(unsigned long long int parentReadingList, const QString &databasePath);
void setupFavoritesModelData(const QString &databasePath);
void setupReadingModelData(const QString &databasePath);
//configures the model for showing the comics matching the filter criteria.
void setupModelData(const SearchModifiers modifier, const QString &filter, const QString &databasePath);

//Métodos de conveniencia
QStringList getPaths(const QString &_source);
Expand Down Expand Up @@ -142,6 +139,8 @@ public slots:
void addComicsToLabel(const QList<qulonglong> &comicIds, qulonglong labelId);
void addComicsToReadingList(const QList<qulonglong> &comicIds, qulonglong readingListId);

void setModelData(QList<ComicItem *> *data, const QString &databasePath);

protected:
private:
void setupModelData(QSqlQuery &sqlquery);
Expand All @@ -164,6 +163,5 @@ public slots:
void resortedIndexes(QList<int>);
void newSelectedIndex(const QModelIndex &);
};
//! [0]

#endif
112 changes: 112 additions & 0 deletions 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<QString, QVariant> 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<ComicItem *> *YACReader::ComicQueryResultProcesor::modelData(QSqlQuery &sqlquery)
{
auto list = new QList<ComicItem *>();

int numColumns = sqlquery.record().count();

while (sqlquery.next()) {
QList<QVariant> 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;
}
32 changes: 32 additions & 0 deletions YACReaderLibrary/db/comic_query_result_procesor.h
@@ -0,0 +1,32 @@
#ifndef COMIC_QUERY_RESULT_PROCESOR_H
#define COMIC_QUERY_RESULT_PROCESOR_H

#include <QtCore>
#include <QSqlQuery>

#include "yacreader_global.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<ComicItem *> *, const QString &);

private:
ConcurrentQueue querySearchQueue;

QList<ComicItem *> *modelData(QSqlQuery &sqlquery);
};
};

#endif // COMIC_QUERY_RESULT_PROCESOR_H