Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/library/searchquery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ QString TextFilterNode::toSql() const {
}
QStringList searchClauses;
for (const auto& sqlColumn : m_sqlColumns) {
searchClauses << QString("%1 LIKE %2").arg(sqlColumn, escapedArgument);
searchClauses << QString("%1 IS NOT NULL AND %1 LIKE %2").arg(sqlColumn, escapedArgument);
}
return concatSqlClauses(searchClauses, "OR");
}
Expand Down
114 changes: 62 additions & 52 deletions src/test/searchqueryparsertest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ TEST_F(SearchQueryParserTest, OneTermOneColumn) {
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("artist LIKE '%asdf%'")),
qPrintable(pQuery->toSql()));
qPrintable(QString("artist IS NOT NULL AND artist LIKE '%asdf%'")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, OneTermMultipleColumns) {
Expand All @@ -82,9 +82,10 @@ TEST_F(SearchQueryParserTest, OneTermMultipleColumns) {
pTrack->setAlbum("testASDFtest");
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("(artist LIKE '%asdf%') OR (album LIKE '%asdf%')")),
qPrintable(pQuery->toSql()));
EXPECT_STREQ(qPrintable(QString(
"(artist IS NOT NULL AND artist LIKE '%asdf%') OR "
"(album IS NOT NULL AND album LIKE '%asdf%')")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, OneTermMultipleColumnsNegation) {
Expand All @@ -98,9 +99,10 @@ TEST_F(SearchQueryParserTest, OneTermMultipleColumnsNegation) {
pTrack->setAlbum("testASDFtest");
EXPECT_FALSE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("NOT ((artist LIKE '%asdf%') OR (album LIKE '%asdf%'))")),
qPrintable(pQuery->toSql()));
EXPECT_STREQ(qPrintable(QString(
"NOT ((artist IS NOT NULL AND artist LIKE '%asdf%') "
"OR (album IS NOT NULL AND album LIKE '%asdf%'))")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, MultipleTermsOneColumn) {
Expand All @@ -114,9 +116,10 @@ TEST_F(SearchQueryParserTest, MultipleTermsOneColumn) {
pTrack->setArtist("test zXcV test asDf");
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("(artist LIKE '%asdf%') AND (artist LIKE '%zxcv%')")),
qPrintable(pQuery->toSql()));
EXPECT_STREQ(qPrintable(QString(
"(artist IS NOT NULL AND artist LIKE '%asdf%') AND "
"(artist IS NOT NULL AND artist LIKE '%zxcv%')")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, MultipleTermsMultipleColumns) {
Expand All @@ -134,11 +137,12 @@ TEST_F(SearchQueryParserTest, MultipleTermsMultipleColumns) {
pTrack->setAlbum("ASDF ZXCV");
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString(
"((artist LIKE '%asdf%') OR (album LIKE '%asdf%')) "
"AND ((artist LIKE '%zxcv%') OR (album LIKE '%zxcv%'))")),
qPrintable(pQuery->toSql()));
EXPECT_STREQ(qPrintable(QString(
"((artist IS NOT NULL AND artist LIKE '%asdf%') OR "
"(album IS NOT NULL AND album LIKE '%asdf%')) "
"AND ((artist IS NOT NULL AND artist LIKE '%zxcv%') "
"OR (album IS NOT NULL AND album LIKE '%zxcv%'))")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, MultipleTermsMultipleColumnsNegation) {
Expand All @@ -158,10 +162,12 @@ TEST_F(SearchQueryParserTest, MultipleTermsMultipleColumnsNegation) {
EXPECT_FALSE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString(
"((artist LIKE '%asdf%') OR (album LIKE '%asdf%')) "
"AND (NOT ((artist LIKE '%zxcv%') OR (album LIKE '%zxcv%')))")),
qPrintable(pQuery->toSql()));
qPrintable(QString(
"((artist IS NOT NULL AND artist LIKE '%asdf%') OR (album "
"IS NOT NULL AND album LIKE '%asdf%')) "
"AND (NOT ((artist IS NOT NULL AND artist LIKE '%zxcv%') "
"OR (album IS NOT NULL AND album LIKE '%zxcv%')))")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, TextFilter) {
Expand All @@ -176,8 +182,8 @@ TEST_F(SearchQueryParserTest, TextFilter) {
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("comment LIKE '%asdf%'")),
qPrintable(pQuery->toSql()));
qPrintable(QString("comment IS NOT NULL AND comment LIKE '%asdf%'")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, TextFilterEquals) {
Expand All @@ -191,7 +197,7 @@ TEST_F(SearchQueryParserTest, TextFilterEquals) {
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("comment LIKE 'asdf'")),
qPrintable(QString("comment IS NOT NULL AND comment LIKE 'asdf'")),
qPrintable(pQuery->toSql()));

// Incomplete quoting should use StringMatch::Contains,
Expand All @@ -202,7 +208,7 @@ TEST_F(SearchQueryParserTest, TextFilterEquals) {
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("comment LIKE '%asdf%'")),
qPrintable(QString("comment IS NOT NULL AND comment LIKE '%asdf%'")),
qPrintable(pQuery->toSql()));
}

Expand Down Expand Up @@ -233,8 +239,8 @@ TEST_F(SearchQueryParserTest, TextFilterQuote) {
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("comment LIKE '%asdf zxcv%'")),
qPrintable(pQuery->toSql()));
qPrintable(QString("comment IS NOT NULL AND comment LIKE '%asdf zxcv%'")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, TextFilterQuote_NoEndQuoteTakesWholeQuery) {
Expand All @@ -249,8 +255,8 @@ TEST_F(SearchQueryParserTest, TextFilterQuote_NoEndQuoteTakesWholeQuery) {
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("comment LIKE '%asdf zxcv qwer%'")),
qPrintable(pQuery->toSql()));
qPrintable(QString("comment IS NOT NULL AND comment LIKE '%asdf zxcv qwer%'")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, TextFilterAllowsSpace) {
Expand All @@ -265,8 +271,8 @@ TEST_F(SearchQueryParserTest, TextFilterAllowsSpace) {
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("comment LIKE '%asdf%'")),
qPrintable(pQuery->toSql()));
qPrintable(QString("comment IS NOT NULL AND comment LIKE '%asdf%'")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, TextFilterQuotes) {
Expand All @@ -281,8 +287,8 @@ TEST_F(SearchQueryParserTest, TextFilterQuotes) {
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("comment LIKE '%asdf ewe%'")),
qPrintable(pQuery->toSql()));
qPrintable(QString("comment IS NOT NULL AND comment LIKE '%asdf ewe%'")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, TextFilterDecoration) {
Expand All @@ -302,9 +308,9 @@ TEST_F(SearchQueryParserTest, TextFilterDecoration) {

qDebug() << pQuery->toSql();

EXPECT_STREQ(
qPrintable(QString::fromUtf8("comment LIKE '%asdf\xC2\xB0 ewe%'")),
qPrintable(pQuery->toSql()));
EXPECT_STREQ(qPrintable(QString::fromUtf8("comment IS NOT NULL AND comment "
"LIKE '%asdf\xC2\xB0 ewe%'")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, TextFilterTrailingSpace) {
Expand All @@ -319,8 +325,8 @@ TEST_F(SearchQueryParserTest, TextFilterTrailingSpace) {
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("comment LIKE '%asdf _%'")),
qPrintable(pQuery->toSql()));
qPrintable(QString("comment IS NOT NULL AND comment LIKE '%asdf _%'")),
qPrintable(pQuery->toSql()));

// We allow to search for two consequitve spaces
auto pQuery2(
Expand All @@ -329,8 +335,8 @@ TEST_F(SearchQueryParserTest, TextFilterTrailingSpace) {
EXPECT_FALSE(pQuery2->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("comment LIKE '% _%'")),
qPrintable(pQuery2->toSql()));
qPrintable(QString("comment IS NOT NULL AND comment LIKE '% _%'")),
qPrintable(pQuery2->toSql()));
}

TEST_F(SearchQueryParserTest, TextFilterNegation) {
Expand All @@ -345,8 +351,8 @@ TEST_F(SearchQueryParserTest, TextFilterNegation) {
EXPECT_FALSE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("NOT (comment LIKE '%asdf%')")),
qPrintable(pQuery->toSql()));
qPrintable(QString("NOT (comment IS NOT NULL AND comment LIKE '%asdf%')")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, NumericFilter) {
Expand Down Expand Up @@ -627,11 +633,14 @@ TEST_F(SearchQueryParserTest, MultipleFilters) {
pTrack->setTitle("Colorvision");
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(qPrintable(QString("(bpm BETWEEN 127.12 AND 129) AND "
"((artist LIKE '%com truise%') OR "
"(album_artist LIKE '%com truise%')) AND "
"((artist LIKE '%colorvision%') OR (title "
"LIKE '%colorvision%'))")),
EXPECT_STREQ(
qPrintable(QString(
"(bpm BETWEEN 127.12 AND 129) AND "
"((artist IS NOT NULL AND artist LIKE '%com truise%') OR "
"(album_artist IS NOT NULL AND album_artist LIKE '%com "
"truise%')) AND "
"((artist IS NOT NULL AND artist LIKE '%colorvision%') OR "
"(title IS NOT NULL AND title LIKE '%colorvision%'))")),
qPrintable(pQuery->toSql()));
}

Expand All @@ -647,8 +656,8 @@ TEST_F(SearchQueryParserTest, ExtraFilterAppended) {
EXPECT_TRUE(pQuery->match(pTrack));

EXPECT_STREQ(
qPrintable(QString("(1 > 2) AND (artist LIKE '%asdf%')")),
qPrintable(pQuery->toSql()));
qPrintable(QString("(1 > 2) AND (artist IS NOT NULL AND artist LIKE '%asdf%')")),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, HumanReadableDurationSearch) {
Expand Down Expand Up @@ -1015,10 +1024,11 @@ TEST_F(SearchQueryParserTest, CrateFilterWithOther){
EXPECT_TRUE(pQuery->match(pTrackA));
EXPECT_FALSE(pQuery->match(pTrackB));

EXPECT_STREQ(
qPrintable("(" + m_crateFilterQuery.arg(searchTerm) +
") AND ((artist LIKE '%asdf%') OR (album_artist LIKE '%asdf%'))"),
qPrintable(pQuery->toSql()));
EXPECT_STREQ(qPrintable("(" + m_crateFilterQuery.arg(searchTerm) +
") AND ((artist IS NOT NULL AND artist LIKE '%asdf%') "
"OR (album_artist IS NOT NULL AND album_artist LIKE "
"'%asdf%'))"),
qPrintable(pQuery->toSql()));
}

TEST_F(SearchQueryParserTest, CrateFilterWithCrateFilterAndNegation){
Expand Down