sqlitesearch: improve tokenizer and fix sort handling

This commit is contained in:
Albert S. 2019-05-04 20:40:43 +02:00
parent 6bb53b8c31
commit 4a8d994358

View File

@ -20,10 +20,11 @@ QVector<SqliteSearch::Token> SqliteSearch::tokenize(QString expression)
} }
// TODO: merge lonewords // TODO: merge lonewords
QVector<SqliteSearch::Token> result; QVector<SqliteSearch::Token> result;
QRegularExpression rx("((?<filtername>(\\.|\\w)+):(?<args>\\((?<innerargs>[^\\)]+)\\)|(\\w)+)|(?<boolean>AND|OR|!)|" QRegularExpression rx("((?<filtername>(\\.|\\w)+):(?<args>\\((?<innerargs>[^\\)]+)\\)|([\\w,])+)|(?<boolean>AND|OR|"
"(?<bracket>\\(|\\))|(?<loneword>\\w+))"); "!)|(?<bracket>\\(|\\))|(?<loneword>\\w+))");
QRegularExpressionMatchIterator i = rx.globalMatch(expression); QRegularExpressionMatchIterator i = rx.globalMatch(expression);
bool wasbool = true; auto isSort = [](QString &key) { return key == "sort"; };
auto isBool = [](QString &key) { return key == "AND" || key == "OR" || key == "!"; };
while(i.hasNext()) while(i.hasNext())
{ {
QRegularExpressionMatch m = i.next(); QRegularExpressionMatch m = i.next();
@ -34,39 +35,34 @@ QVector<SqliteSearch::Token> SqliteSearch::tokenize(QString expression)
if(boolean != "") if(boolean != "")
{ {
wasbool = true;
result.append(Token(boolean)); result.append(Token(boolean));
} }
if(!result.empty())
{
QString &lastKey = result.last().key;
if(!isBool(lastKey) && !isSort(lastKey) && !isSort(filtername))
{
result.append(Token("AND"));
}
}
if(bracket != "") if(bracket != "")
{
if(!wasbool)
{ {
if(bracket == "(") if(bracket == "(")
{ {
result.append(Token("AND")); result.append(Token("AND"));
} }
}
result.append(Token(bracket)); result.append(Token(bracket));
} }
if(loneword != "") if(loneword != "")
{ {
if(!wasbool)
{
result.append(Token("AND"));
}
wasbool = false;
result.append(Token("path.contains", loneword)); result.append(Token("path.contains", loneword));
} }
if(filtername != "") if(filtername != "")
{ {
if(!wasbool)
{
result.append(Token("AND"));
}
wasbool = false;
QString value = m.captured("innerargs"); QString value = m.captured("innerargs");
if(value == "") if(value == "")
{ {
@ -109,15 +105,27 @@ QString SqliteSearch::createSortSql(const SqliteSearch::Token &token)
for(int i = 0; i < splitted_inner.length(); i++) for(int i = 0; i < splitted_inner.length(); i++)
{ {
QStringList splitted = splitted_inner[i].split(" "); QStringList splitted = splitted_inner[i].split(" ");
if(splitted.length() < 1 || splitted.length() > 2)
{
throw QSSGeneralException("sort specifier must have format [field] (asc|desc)");
}
QString field = splitted[0];
field = fieldToColumn(field);
if(field == "")
{
throw QSSGeneralException("Unknown sort field supplied");
}
QString order;
if(splitted.length() == 2) if(splitted.length() == 2)
{ {
QString field = splitted[0]; order = splitted[1];
QString order = splitted[1]; if(order.compare("asc", Qt::CaseInsensitive) == 0)
if(order.compare("asc", Qt::CaseInsensitive))
{ {
order = "ASC"; order = "ASC";
} }
else if(order.compare("desc", Qt::CaseInsensitive)) else if(order.compare("desc", Qt::CaseInsensitive) == 0)
{ {
order = "DESC"; order = "DESC";
} }
@ -125,11 +133,10 @@ QString SqliteSearch::createSortSql(const SqliteSearch::Token &token)
{ {
throw QSSGeneralException("Unknown order specifier: " + order); throw QSSGeneralException("Unknown order specifier: " + order);
} }
}
field = fieldToColumn(field); else
if(field == "")
{ {
throw QSSGeneralException("Unknown field:" + field); order = "ASC";
} }
sortsql += field + " " + order; sortsql += field + " " + order;
@ -138,16 +145,7 @@ QString SqliteSearch::createSortSql(const SqliteSearch::Token &token)
sortsql += ", "; sortsql += ", ";
} }
} }
else if(splitted.length() == 1) return " ORDER BY " + sortsql;
{
sortsql += splitted[0] + " ASC ";
}
else
{
throw QSSGeneralException("sort specifier must have format [field] (asc|desc)");
}
}
return sortsql;
} }
return ""; return "";
} }
@ -221,6 +219,10 @@ QSqlQuery SqliteSearch::makeSqlQuery(const QVector<SqliteSearch::Token> &tokens)
} }
QString prepSql; QString prepSql;
if(whereSql.isEmpty())
{
throw QSSGeneralException("Nothing to search for supplied");
}
if(isContentSearch) if(isContentSearch)
{ {
if(sortSql.isEmpty()) if(sortSql.isEmpty())
@ -238,6 +240,11 @@ QSqlQuery SqliteSearch::makeSqlQuery(const QVector<SqliteSearch::Token> &tokens)
{ {
sortSql = "ORDER BY file.mtime DESC"; sortSql = "ORDER BY file.mtime DESC";
} }
if(sortSql.contains("content."))
{
throw QSSGeneralException("Cannot sort for content fields when not doing a content search");
}
prepSql = "SELECT file.path AS path, '0' as pages, file.mtime AS mtime, file.size AS size, file.filetype AS " prepSql = "SELECT file.path AS path, '0' as pages, file.mtime AS mtime, file.size AS size, file.filetype AS "
"filetype FROM file WHERE 1=1 AND " + "filetype FROM file WHERE 1=1 AND " +
whereSql + " " + sortSql; whereSql + " " + sortSql;