Skip to content

Commit

Permalink
Track search: '=' and quoted strings looks for exact matches
Browse files Browse the repository at this point in the history
  • Loading branch information
ronso0 committed Oct 5, 2023
1 parent 17362a7 commit 42ba552
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 9 deletions.
25 changes: 19 additions & 6 deletions src/library/searchquery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,12 @@ QString NotNode::toSql() const {

TextFilterNode::TextFilterNode(const QSqlDatabase& database,
const QStringList& sqlColumns,
const QString& argument)
const QString& argument,
bool exactMatch)
: m_database(database),
m_sqlColumns(sqlColumns),
m_argument(argument) {
m_argument(argument),
m_exactMatch(exactMatch) {
mixxx::DbConnection::makeStringLatinLow(&m_argument);
}

Expand All @@ -184,8 +186,14 @@ bool TextFilterNode::match(const TrackPointer& pTrack) const {

QString strValue = value.toString();
mixxx::DbConnection::makeStringLatinLow(&strValue);
if (strValue.contains(m_argument)) {
return true;
if (m_exactMatch) {
if (strValue == m_argument) {
return true;
}
} else {
if (strValue.contains(m_argument)) {
return true;
}
}
}
return false;
Expand All @@ -201,8 +209,13 @@ QString TextFilterNode::toSql() const {
argument.append('_');
}
}
QString escapedArgument = escaper.escapeString(
kSqlLikeMatchAll + argument + kSqlLikeMatchAll);
QString escapedArgument;
if (m_exactMatch) {
escapedArgument = escaper.escapeString(argument);
} else {
escapedArgument = escaper.escapeString(
kSqlLikeMatchAll + argument + kSqlLikeMatchAll);
}
QStringList searchClauses;
for (const auto& sqlColumn : m_sqlColumns) {
searchClauses << QString("%1 LIKE %2").arg(sqlColumn, escapedArgument);
Expand Down
4 changes: 3 additions & 1 deletion src/library/searchquery.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ class TextFilterNode : public QueryNode {
public:
TextFilterNode(const QSqlDatabase& database,
const QStringList& sqlColumns,
const QString& argument);
const QString& argument,
bool exactMatch = false);

bool match(const TrackPointer& pTrack) const override;
QString toSql() const override;
Expand All @@ -81,6 +82,7 @@ class TextFilterNode : public QueryNode {
QSqlDatabase m_database;
QStringList m_sqlColumns;
QString m_argument;
bool m_exactMatch;
};

class NullOrEmptyTextFilterNode : public QueryNode {
Expand Down
40 changes: 39 additions & 1 deletion src/library/searchqueryparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ SearchQueryParser::SearchQueryParser(TrackCollection* pTrackCollection, QStringL

m_fuzzyMatcher = QRegularExpression(QString("^~(%1)$").arg(m_allFilters.join("|")));
m_textFilterMatcher = QRegularExpression(QString("^-?(%1):(.*)$").arg(m_textFilters.join("|")));
m_textFilterExactMatcher = QRegularExpression(
QString("^-?(%1)=(.*)$").arg(m_textFilters.join("|")));
m_numericFilterMatcher = QRegularExpression(
QString("^-?(%1):(.*)$").arg(m_numericFilters.join("|")));
m_specialFilterMatcher = QRegularExpression(
Expand All @@ -88,7 +90,8 @@ void SearchQueryParser::setSearchColumns(QStringList searchColumns) {
}

QString SearchQueryParser::getTextArgument(QString argument,
QStringList* tokens) const {
QStringList* tokens,
bool* exactMatch) const {
// If the argument is empty, assume the user placed a space after an
// advanced search command. Consume another token and treat that as the
// argument.
Expand Down Expand Up @@ -128,8 +131,12 @@ QString SearchQueryParser::getTextArgument(QString argument,
// return it as "" to distinguish it from an unfinished empty string
argument = kMissingFieldSearchTerm;
} else {
// Found a closing quote.
// Slice off the quote and everything after.
argument = argument.left(quote_index);
if (exactMatch != nullptr) {
*exactMatch = true;
}
}
}

Expand All @@ -149,6 +156,7 @@ void SearchQueryParser::parseTokens(QStringList tokens,

const QRegularExpressionMatch fuzzyMatch = m_fuzzyMatcher.match(token);
const QRegularExpressionMatch textFilterMatch = m_textFilterMatcher.match(token);
const QRegularExpressionMatch textFilterExactMatch = m_textFilterExactMatcher.match(token);
const QRegularExpressionMatch numericFilterMatch = m_numericFilterMatcher.match(token);
const QRegularExpressionMatch specialFilterMatch = m_specialFilterMatcher.match(token);
if (fuzzyMatch.hasMatch()) {
Expand Down Expand Up @@ -179,6 +187,36 @@ void SearchQueryParser::parseTokens(QStringList tokens,
m_fieldToSqlColumns[field], argument);
}
}
} else if (textFilterExactMatch.hasMatch()) {
QString field = textFilterExactMatch.captured(1);
bool exactMatch = false;
QString argument = getTextArgument(
textFilterExactMatch.captured(2), &tokens, &exactMatch);

if (argument == kMissingFieldSearchTerm) {
qDebug() << "argument explicit empty";
if (field == "crate") {
pNode = std::make_unique<NoCrateFilterNode>(
&m_pTrackCollection->crates());
qDebug() << pNode->toSql();
} else {
pNode = std::make_unique<NullOrEmptyTextFilterNode>(
m_pTrackCollection->database(), m_fieldToSqlColumns[field]);
qDebug() << pNode->toSql();
}
} else if (!argument.isEmpty()) {
if (field == "crate") {
pNode = std::make_unique<CrateFilterNode>(
&m_pTrackCollection->crates(), argument);
//&m_pTrackCollection->crates(), argument, exactMatch);
} else {
pNode = std::make_unique<TextFilterNode>(
m_pTrackCollection->database(),
m_fieldToSqlColumns[field],
argument,
exactMatch);
}
}
} else if (numericFilterMatch.hasMatch()) {
QString field = numericFilterMatch.captured(1);
QString argument = getTextArgument(
Expand Down
4 changes: 3 additions & 1 deletion src/library/searchqueryparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class SearchQueryParser {
AndNode* pQuery) const;

QString getTextArgument(QString argument,
QStringList* tokens) const;
QStringList* tokens,
bool* exactMatch = nullptr) const;

TrackCollection* m_pTrackCollection;
QStringList m_queryColumns;
Expand All @@ -43,6 +44,7 @@ class SearchQueryParser {

QRegularExpression m_fuzzyMatcher;
QRegularExpression m_textFilterMatcher;
QRegularExpression m_textFilterExactMatcher;
QRegularExpression m_crateFilterMatcher;
QRegularExpression m_numericFilterMatcher;
QRegularExpression m_specialFilterMatcher;
Expand Down

0 comments on commit 42ba552

Please sign in to comment.