Skip to content

Commit 383e343

Browse files
committed
BasetrackCache: fix false positive tracks results when using extra filter
1 parent 1b35136 commit 383e343

File tree

3 files changed

+45
-22
lines changed

3 files changed

+45
-22
lines changed
Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
11
#include "library/analysis/analysislibrarytablemodel.h"
22

3+
#include <QDateTime>
4+
35
#include "moc_analysislibrarytablemodel.cpp"
6+
#include "util/datetime.h"
47

58
namespace {
69

7-
const QString RECENT_FILTER = "datetime_added > datetime('now', '-7 days')";
10+
inline QString recentFilter() {
11+
// Create a user-formatted query equal to SQL query
12+
// datetime_added > datetime('now', '-7 days')
13+
QDateTime dt(QDateTime::currentDateTimeUtc());
14+
dt = dt.addDays(-7);
15+
const QString dateStr = QLocale::system().toString(dt.date(), QLocale::ShortFormat);
16+
17+
// FIXME alternatively, use "added:-days" and add the respective
18+
// literal parser to DateAddedFilterNode
19+
return QStringLiteral("added:>%1").arg(dateStr);
20+
}
821

922
} // anonymous namespace
1023

@@ -13,12 +26,12 @@ AnalysisLibraryTableModel::AnalysisLibraryTableModel(QObject* parent,
1326
: LibraryTableModel(parent, pTrackCollectionManager,
1427
"mixxx.db.model.prepare") {
1528
// Default to showing recent tracks.
16-
setSearch("", RECENT_FILTER);
29+
setSearch("", recentFilter());
1730
}
1831

1932
void AnalysisLibraryTableModel::showRecentSongs() {
2033
// Search with the recent filter.
21-
search(currentSearch(), RECENT_FILTER);
34+
search(currentSearch(), recentFilter());
2235
}
2336

2437
void AnalysisLibraryTableModel::showAllSongs() {
@@ -27,5 +40,5 @@ void AnalysisLibraryTableModel::showAllSongs() {
2740
}
2841

2942
void AnalysisLibraryTableModel::searchCurrentTrackSet(const QString& text, bool useRecentFilter) {
30-
search(text, useRecentFilter ? RECENT_FILTER : "");
43+
search(text, useRecentFilter ? recentFilter() : "");
3144
}

src/library/basesqltablemodel.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,9 @@ void BaseSqlTableModel::setSearch(const QString& searchText, const QString& extr
422422
return;
423423
}
424424

425+
// Note: don't use SQL strings as extraFilter, this will cause issues in
426+
// BaseTrackCache::filterAndSort() which is responsible for adding/removing
427+
// dirty tracks from the view.
425428
m_currentSearch = searchText;
426429
m_currentSearchFilter = extraFilter;
427430
}

src/library/basetrackcache.cpp

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -458,30 +458,35 @@ void BaseTrackCache::filterAndSort(const QSet<TrackId>& trackIds,
458458
buildIndex();
459459
}
460460

461+
// The id string we need for our QSqlQuery
461462
QStringList idStrings;
463+
// The id set we need for removing/adding dirty tracks
464+
QSet<TrackId> ids;
462465
// TODO(rryan) consider making this the data passed in and a separate
463466
// QVector for output
464467
QSet<TrackId> dirtyTracks;
465-
for (const auto& trackId: trackIds) {
468+
for (const auto& trackId : trackIds) {
466469
idStrings << trackId.toString();
470+
ids << trackId;
467471
if (m_dirtyTracks.contains(trackId)) {
468472
dirtyTracks.insert(trackId);
469473
}
470474
}
471475

472-
QStringList queryFragments;
473-
if (!extraFilter.isNull() && extraFilter != "") {
474-
queryFragments << QString("(%1)").arg(extraFilter);
475-
}
476-
if (idStrings.size() > 0) {
477-
queryFragments << QString("%1 in (%2)")
478-
.arg(m_idColumn, idStrings.join(","));
476+
// Note: don't use the extraFilter for m_pQueryParser->parseQuery(), just
477+
// append it to searchQuery if not empty and let the parser construct
478+
// a SQL query from it.
479+
// The issue with the extraFilter is that the parser is assuming the input
480+
// is a SQL string and creates a SqlNode from it, and the issue with that is
481+
// that SqlNode::match(TrackPointer) always returns true -- which leads to
482+
// false positive matches when we iterate over the dirty tracks below.
483+
QString searchPlusExtraFilter = searchQuery;
484+
if (!extraFilter.isEmpty()) {
485+
searchPlusExtraFilter += ' ';
486+
searchPlusExtraFilter += extraFilter;
479487
}
480-
481488
const std::unique_ptr<QueryNode> pQuery =
482-
m_pQueryParser->parseQuery(
483-
searchQuery,
484-
queryFragments.join(" AND "));
489+
m_pQueryParser->parseQuery(searchPlusExtraFilter, QString());
485490

486491
QString filter = pQuery->toSql();
487492
if (!filter.isEmpty()) {
@@ -539,18 +544,20 @@ void BaseTrackCache::filterAndSort(const QSet<TrackId>& trackIds,
539544
}
540545

541546
for (TrackId trackId : std::as_const(dirtyTracks)) {
542-
// Only get the track if it is in the cache. Tracks that
543-
// are not cached in memory cannot be dirty.
547+
// Only get the track if it is in the cache.
548+
// Tracks that are not cached in memory cannot be dirty.
544549
// Bypass getCachedTrack() to not invalidate m_recentTrackId
545550
TrackPointer pTrack = GlobalTrackCacheLocker().lookupTrackById(trackId);
546551
if (!pTrack) {
547552
continue;
548553
}
549554

550-
// The track should be in the result set if the search is empty or the
551-
// track matches the search.
552-
bool shouldBeInResultSet = searchQuery.isEmpty() ||
553-
pQuery->match(pTrack);
555+
// The track should be in the result set if
556+
// the search and extra filter are empty
557+
// or
558+
// the track matches the search and ids (if not empty) contains its id
559+
bool shouldBeInResultSet = searchPlusExtraFilter.isEmpty() ||
560+
((ids.isEmpty() || ids.contains(trackId)) && pQuery->match(pTrack));
554561

555562
// If the track is in this result set.
556563
bool isInResultSet = trackToIndex->contains(trackId);

0 commit comments

Comments
 (0)