checks on input, exceptions, improved contains query performance
This commit is contained in:
parent
d9b01a4941
commit
7a485c55bb
@ -35,6 +35,7 @@ void MainWindow::connectSignals()
|
|||||||
connect(this, &MainWindow::beginSearch, searchWorker, &SearchWorker::search);
|
connect(this, &MainWindow::beginSearch, searchWorker, &SearchWorker::search);
|
||||||
connect(searchWorker, &SearchWorker::searchResultsReady, this, &MainWindow::handleSearchResults);
|
connect(searchWorker, &SearchWorker::searchResultsReady, this, &MainWindow::handleSearchResults);
|
||||||
connect(searchWorker, &SearchWorker::searchCancelled, this, &MainWindow::handleCancelledSearch);
|
connect(searchWorker, &SearchWorker::searchCancelled, this, &MainWindow::handleCancelledSearch);
|
||||||
|
connect(searchWorker, &SearchWorker::searchError, this, &MainWindow::handleSearchError);
|
||||||
connect(ui->treeResultsList, &QTreeWidget::itemActivated, this, &MainWindow::treeSearchItemActivated);
|
connect(ui->treeResultsList, &QTreeWidget::itemActivated, this, &MainWindow::treeSearchItemActivated);
|
||||||
connect(ui->treeResultsList, &QTreeWidget::customContextMenuRequested, this,
|
connect(ui->treeResultsList, &QTreeWidget::customContextMenuRequested, this,
|
||||||
&MainWindow::showSearchResultsContextMenu);
|
&MainWindow::showSearchResultsContextMenu);
|
||||||
@ -99,6 +100,11 @@ void MainWindow::pdfPreviewReceived(PdfPreview preview)
|
|||||||
void MainWindow::lineEditReturnPressed()
|
void MainWindow::lineEditReturnPressed()
|
||||||
{
|
{
|
||||||
QString q = ui->txtSearch->text();
|
QString q = ui->txtSearch->text();
|
||||||
|
if(!searchWorker->checkParanthesis(q))
|
||||||
|
{
|
||||||
|
ui->lblSearchResults->setText("Invalid paranthesis");
|
||||||
|
return;
|
||||||
|
}
|
||||||
// TODO: validate q;
|
// TODO: validate q;
|
||||||
ui->lblSearchResults->setText("Searching...");
|
ui->lblSearchResults->setText("Searching...");
|
||||||
emit beginSearch(q);
|
emit beginSearch(q);
|
||||||
@ -156,6 +162,11 @@ void MainWindow::handleCancelledSearch()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::handleSearchError(QString error)
|
||||||
|
{
|
||||||
|
ui->lblSearchResults->setText("Error:" + error);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::treeSearchItemActivated(QTreeWidgetItem *item, int i)
|
void MainWindow::treeSearchItemActivated(QTreeWidgetItem *item, int i)
|
||||||
{
|
{
|
||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(item->text(1)));
|
QDesktopServices::openUrl(QUrl::fromLocalFile(item->text(1)));
|
||||||
|
@ -42,8 +42,8 @@ class MainWindow : public QMainWindow
|
|||||||
void lineEditReturnPressed();
|
void lineEditReturnPressed();
|
||||||
void handleSearchResults(const QVector<SearchResult> &results);
|
void handleSearchResults(const QVector<SearchResult> &results);
|
||||||
void handleCancelledSearch();
|
void handleCancelledSearch();
|
||||||
|
void handleSearchError(QString error);
|
||||||
void treeSearchItemActivated(QTreeWidgetItem *item, int i);
|
void treeSearchItemActivated(QTreeWidgetItem *item, int i);
|
||||||
|
|
||||||
void showSearchResultsContextMenu(const QPoint &point);
|
void showSearchResultsContextMenu(const QPoint &point);
|
||||||
void tabChanged();
|
void tabChanged();
|
||||||
void pdfPreviewReceived(PdfPreview preview);
|
void pdfPreviewReceived(PdfPreview preview);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QSqlError>
|
#include <QSqlError>
|
||||||
|
#include <QStack>
|
||||||
SearchWorker::SearchWorker()
|
SearchWorker::SearchWorker()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -18,6 +19,10 @@ SearchWorker::SearchWorker(const QString &dbpath)
|
|||||||
|
|
||||||
QVector<SearchWorker::Command> SearchWorker::tokenize(QString expression)
|
QVector<SearchWorker::Command> SearchWorker::tokenize(QString expression)
|
||||||
{
|
{
|
||||||
|
if(!checkParanthesis(expression))
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Invalid paranthesis");
|
||||||
|
}
|
||||||
// TODO: merge lonewords
|
// TODO: merge lonewords
|
||||||
QVector<Command> result;
|
QVector<Command> result;
|
||||||
QRegularExpression rx("((?<filtername>(\\.|\\w)+):(?<args>\\((?<innerargs>[^\\)]+)\\)|(\\w)+)|(?<boolean>AND|OR|!)|"
|
QRegularExpression rx("((?<filtername>(\\.|\\w)+):(?<args>\\((?<innerargs>[^\\)]+)\\)|(\\w)+)|(?<boolean>AND|OR|!)|"
|
||||||
@ -108,12 +113,10 @@ QString SearchWorker::createSql(const SearchWorker::Command &cmd)
|
|||||||
}
|
}
|
||||||
if(key == "contains" || key == "c")
|
if(key == "contains" || key == "c")
|
||||||
{
|
{
|
||||||
return " ( COALESCE( (SELECT 1 FROM content_fts WHERE content_fts.content MATCH '" + value +
|
return " content.id IN (SELECT content_fts.ROWID FROM content_fts WHERE content_fts.content MATCH '" + value +
|
||||||
"' AND content_fts.ROWID= content.id), 0 ) )";
|
"' )";
|
||||||
}
|
}
|
||||||
qDebug() << "NOHIT" << key;
|
throw std::invalid_argument("Unknown filter: " + key.toStdString());
|
||||||
// TODO: exception?
|
|
||||||
return "NOTHING";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SearchWorker::makeSql(const QVector<SearchWorker::Command> &tokens)
|
QString SearchWorker::makeSql(const QVector<SearchWorker::Command> &tokens)
|
||||||
@ -126,18 +129,59 @@ QString SearchWorker::makeSql(const QVector<SearchWorker::Command> &tokens)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SearchWorker::checkParanthesis(QString expression)
|
||||||
|
{
|
||||||
|
QStack<QChar> open;
|
||||||
|
QStack<QChar> close;
|
||||||
|
|
||||||
|
for(QChar &c : expression)
|
||||||
|
{
|
||||||
|
if(c == '(')
|
||||||
|
{
|
||||||
|
open.push(c);
|
||||||
|
}
|
||||||
|
if(c == ')')
|
||||||
|
{
|
||||||
|
close.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(open.size() != close.size())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while(!open.empty() && !close.empty())
|
||||||
|
{
|
||||||
|
QChar o = open.pop();
|
||||||
|
QChar c = close.pop();
|
||||||
|
if(o != '(' && c != ')')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void SearchWorker::search(const QString &query)
|
void SearchWorker::search(const QString &query)
|
||||||
{
|
{
|
||||||
QSqlQuery dbquery(db);
|
QSqlQuery dbquery(db);
|
||||||
QVector<SearchResult> results;
|
QVector<SearchResult> results;
|
||||||
QString whereSql = makeSql(tokenize(query));
|
QString whereSql;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
whereSql = makeSql(tokenize(query));
|
||||||
|
}
|
||||||
|
catch(const std::exception &e)
|
||||||
|
{
|
||||||
|
emit searchError(e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QString prep;
|
QString prep;
|
||||||
// TODO: hack, as we don't wanna look into content and get redundant results, when we don't even care about content
|
// TODO: hack, as we don't wanna look into content and get redundant results, when we don't even care about content
|
||||||
if(whereSql.contains("content."))
|
if(whereSql.contains("content."))
|
||||||
{
|
{
|
||||||
prep = "SELECT file.path AS path, content.page AS page, file.mtime AS mtime FROM file INNER JOIN content ON "
|
prep = "SELECT file.path AS path, content.page AS page, file.mtime AS mtime FROM file INNER JOIN content ON "
|
||||||
"file.id = content.fileid INNER JOIN content_fts ON content.id = content_fts.ROWID WHERE 1=1 AND " +
|
"file.id = content.fileid WHERE 1=1 AND " +
|
||||||
whereSql + " ORDER By file.mtime DESC, content.page ASC";
|
whereSql + " ORDER By file.mtime DESC, content.page ASC";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -146,9 +190,15 @@ void SearchWorker::search(const QString &query)
|
|||||||
" ORDER by file.mtime DESC";
|
" ORDER by file.mtime DESC";
|
||||||
}
|
}
|
||||||
dbquery.prepare(prep);
|
dbquery.prepare(prep);
|
||||||
dbquery.exec();
|
bool success = dbquery.exec();
|
||||||
qDebug() << "prepped: " << prep;
|
if(!success)
|
||||||
qDebug() << dbquery.lastError();
|
{
|
||||||
|
qDebug() << "prepped: " << prep;
|
||||||
|
qDebug() << dbquery.lastError();
|
||||||
|
emit searchError(dbquery.lastError().text());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while(dbquery.next())
|
while(dbquery.next())
|
||||||
{
|
{
|
||||||
SearchResult result;
|
SearchResult result;
|
||||||
|
@ -32,11 +32,13 @@ class SearchWorker : public QObject
|
|||||||
public:
|
public:
|
||||||
SearchWorker();
|
SearchWorker();
|
||||||
SearchWorker(const QString &dbpath);
|
SearchWorker(const QString &dbpath);
|
||||||
|
bool checkParanthesis(QString expression);
|
||||||
public slots:
|
public slots:
|
||||||
void search(const QString &query);
|
void search(const QString &query);
|
||||||
signals:
|
signals:
|
||||||
void searchResultsReady(const QVector<SearchResult> &results);
|
void searchResultsReady(const QVector<SearchResult> &results);
|
||||||
void searchCancelled();
|
void searchCancelled();
|
||||||
|
void searchError(QString e);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SEARCHWORKER_H
|
#endif // SEARCHWORKER_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user