Sorting by recently added now uses the 'added' info instead of the 'last write time' of the underlying file, ref #571

This commit is contained in:
emeric
2025-01-21 16:47:57 +01:00
parent 6f214f839e
commit 07e120abf2
13 changed files with 262 additions and 19 deletions
+9 -5
View File
@@ -42,9 +42,9 @@ namespace lms::db
{
session.checkReadTransaction();
// TODO remove distinct and use group by
auto query{ session.getDboSession()->query<ResultType>("SELECT " + std::string{ itemToSelect } + " FROM artist a") };
if (params.sortMethod == ArtistSortMethod::LastWritten
if (params.sortMethod == ArtistSortMethod::LastWrittenDesc
|| params.sortMethod == ArtistSortMethod::AddedDesc
|| params.writtenAfter.isValid()
|| params.linkType
|| params.track.isValid()
@@ -55,7 +55,8 @@ namespace lms::db
query.join("track_artist_link t_a_l ON t_a_l.artist_id = a.id");
}
if (params.sortMethod == ArtistSortMethod::LastWritten
if (params.sortMethod == ArtistSortMethod::LastWrittenDesc
|| params.sortMethod == ArtistSortMethod::AddedDesc
|| params.writtenAfter.isValid()
|| params.release.isValid()
|| params.mediaLibrary.isValid())
@@ -151,8 +152,11 @@ namespace lms::db
case ArtistSortMethod::Random:
query.orderBy("RANDOM()");
break;
case ArtistSortMethod::LastWritten:
query.orderBy("t.file_last_write DESC");
case ArtistSortMethod::LastWrittenDesc:
query.orderBy("MAX(t.file_last_write) DESC");
break;
case ArtistSortMethod::AddedDesc:
query.orderBy("MAX(t.file_added) DESC");
break;
case ArtistSortMethod::StarredDateDesc:
assert(params.starringUser.isValid());
+3
View File
@@ -48,9 +48,12 @@ namespace lms::db
{
prepare();
}
~Connection() override = default;
private:
Connection& operator=(const Connection&) = delete;
Connection(Connection&&) = delete;
Connection&& operator=(Connection&&) = delete;
std::unique_ptr<SqlConnection> clone() const override
{
+6 -2
View File
@@ -50,7 +50,8 @@ namespace lms::db
auto query{ session.getDboSession()->query<ResultType>("SELECT " + std::string{ itemToSelect } + " from release r") };
if (params.sortMethod == ReleaseSortMethod::ArtistNameThenName
|| params.sortMethod == ReleaseSortMethod::LastWritten
|| params.sortMethod == ReleaseSortMethod::LastWrittenDesc
|| params.sortMethod == ReleaseSortMethod::AddedDesc
|| params.sortMethod == ReleaseSortMethod::DateAsc
|| params.sortMethod == ReleaseSortMethod::DateDesc
|| params.sortMethod == ReleaseSortMethod::OriginalDate
@@ -207,9 +208,12 @@ namespace lms::db
case ReleaseSortMethod::Random:
query.orderBy("RANDOM()");
break;
case ReleaseSortMethod::LastWritten:
case ReleaseSortMethod::LastWrittenDesc:
query.orderBy("t.file_last_write DESC");
break;
case ReleaseSortMethod::AddedDesc:
query.orderBy("t.file_added DESC");
break;
case ReleaseSortMethod::DateAsc:
query.orderBy("t.date ASC, r.name COLLATE NOCASE");
break;
+8 -1
View File
@@ -240,7 +240,10 @@ namespace lms::db
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_date_idx ON track(date)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_directory_release_idx ON track(directory_id, release_id);");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_directory_file_stem_idx ON track(directory_id, file_stem);");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_added_idx ON track(file_added)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_added_desc_idx ON track(file_added DESC)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_last_write_idx ON track(file_last_write)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_last_write_desc_idx ON track(file_last_write DESC)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_file_name_idx ON track(file_name COLLATE NOCASE)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_media_library_idx ON track(media_library_id)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_media_library_release_idx ON track(media_library_id, release_id)");
@@ -250,8 +253,12 @@ namespace lms::db
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_original_date_idx ON track(original_date)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_recording_mbid_idx ON track(recording_mbid)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_idx ON track(release_id)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_file_last_write_idx ON track(release_id, file_last_write)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_date_idx ON track(release_id, date)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_date_desc_idx ON track(release_id, date DESC)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_file_last_write_idx ON track(release_id, file_last_write)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_file_last_write_desc_idx ON track(release_id, file_last_write DESC)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_file_added_idx ON track(release_id, file_added)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_release_file_added_desc_idx ON track(release_id, file_added DESC)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS tracklist_name_idx ON tracklist(name)");
utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS tracklist_user_type_idx ON tracklist(user_id, type)");
+4 -1
View File
@@ -175,9 +175,12 @@ namespace lms::db
case TrackSortMethod::Id:
query.orderBy("t.id");
break;
case TrackSortMethod::LastWritten:
case TrackSortMethod::LastWrittenDesc:
query.orderBy("t.file_last_write DESC");
break;
case TrackSortMethod::AddedDesc:
query.orderBy("t.file_added DESC");
break;
case TrackSortMethod::Random:
query.orderBy("RANDOM()");
break;
+6 -3
View File
@@ -119,7 +119,8 @@ namespace lms::db
Name,
SortName,
Random,
LastWritten,
LastWrittenDesc,
AddedDesc,
StarredDateDesc,
};
@@ -146,7 +147,8 @@ namespace lms::db
OriginalDate,
OriginalDateDesc,
Random,
LastWritten,
LastWrittenDesc,
AddedDesc,
StarredDateDesc,
};
@@ -162,7 +164,8 @@ namespace lms::db
None,
Id,
Random,
LastWritten,
LastWrittenDesc,
AddedDesc,
StarredDateDesc,
FileName,
Name,
+92 -3
View File
@@ -669,7 +669,8 @@ namespace lms::db::tests
TEST_F(DatabaseFixture, Artist_findByRelease)
{
ScopedArtist artist{ session, "artist" };
ScopedTrack track{ session };
ScopedTrack track1{ session };
ScopedTrack track2{ session };
ScopedRelease release{ session, "MyRelease" };
{
@@ -680,7 +681,8 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist);
TrackArtistLink::create(session, track1.get(), artist.get(), TrackArtistLinkType::Artist);
TrackArtistLink::create(session, track2.get(), artist.get(), TrackArtistLinkType::Artist);
}
{
@@ -691,7 +693,8 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
track.get().modify()->setRelease(release.get());
track1.get().modify()->setRelease(release.get());
track2.get().modify()->setRelease(release.get());
}
{
@@ -700,6 +703,12 @@ namespace lms::db::tests
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
}
{
auto transaction{ session.createReadTransaction() };
const std::size_t count{ Release::getCount(session, Release::FindParameters{}.setArtist(artist.getId())) };
EXPECT_EQ(count, 1);
}
}
TEST_F(DatabaseFixture, Artist_image)
@@ -725,4 +734,84 @@ namespace lms::db::tests
EXPECT_EQ(artistImage->getId(), image.getId());
}
}
TEST_F(DatabaseFixture, Artist_sortDateAdded)
{
ScopedArtist artistA{ session, "artistA" };
ScopedArtist artistB{ session, "artistB" };
ScopedArtist artistC{ session, "artistC" };
ScopedArtist artistD{ session, "artistD" };
ScopedTrack trackA1{ session };
ScopedTrack trackB1{ session };
ScopedTrack trackC1{ session };
ScopedTrack trackD1{ session };
ScopedTrack trackA2{ session };
{
auto transaction{ session.createWriteTransaction() };
trackA1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2 });
trackB1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 1 });
trackD1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2, 15, 36, 24 });
trackD1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 3 });
trackA2.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 4 });
TrackArtistLink::create(session, trackA1.get(), artistA.get(), TrackArtistLinkType::Artist);
TrackArtistLink::create(session, trackA2.get(), artistA.get(), TrackArtistLinkType::Producer);
TrackArtistLink::create(session, trackB1.get(), artistB.get(), TrackArtistLinkType::Artist);
TrackArtistLink::create(session, trackC1.get(), artistC.get(), TrackArtistLinkType::Artist);
TrackArtistLink::create(session, trackD1.get(), artistD.get(), TrackArtistLinkType::Artist);
}
{
auto transaction{ session.createReadTransaction() };
const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setSortMethod(ArtistSortMethod::AddedDesc)) };
ASSERT_EQ(artists.results.size(), 4);
EXPECT_EQ(artists.results[0], artistA.getId());
EXPECT_EQ(artists.results[1], artistD.getId());
EXPECT_EQ(artists.results[2], artistB.getId());
EXPECT_EQ(artists.results[3], artistC.getId());
}
}
TEST_F(DatabaseFixture, Artist_sortLastWritten)
{
ScopedArtist artistA{ session, "artistA" };
ScopedArtist artistB{ session, "artistB" };
ScopedArtist artistC{ session, "artistC" };
ScopedArtist artistD{ session, "artistD" };
ScopedTrack trackA1{ session };
ScopedTrack trackB1{ session };
ScopedTrack trackC1{ session };
ScopedTrack trackD1{ session };
ScopedTrack trackA2{ session };
{
auto transaction{ session.createWriteTransaction() };
trackA1.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 } });
trackB1.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 1 } });
trackD1.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 }, Wt::WTime{ 15, 36, 24 } });
trackD1.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 3 } });
trackA2.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 4 } });
TrackArtistLink::create(session, trackA1.get(), artistA.get(), TrackArtistLinkType::Artist);
TrackArtistLink::create(session, trackA2.get(), artistA.get(), TrackArtistLinkType::Producer);
TrackArtistLink::create(session, trackB1.get(), artistB.get(), TrackArtistLinkType::Artist);
TrackArtistLink::create(session, trackC1.get(), artistC.get(), TrackArtistLinkType::Artist);
TrackArtistLink::create(session, trackD1.get(), artistD.get(), TrackArtistLinkType::Artist);
}
{
auto transaction{ session.createReadTransaction() };
const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setSortMethod(ArtistSortMethod::LastWrittenDesc)) };
ASSERT_EQ(artists.results.size(), 4);
EXPECT_EQ(artists.results[0], artistA.getId());
EXPECT_EQ(artists.results[1], artistD.getId());
EXPECT_EQ(artists.results[2], artistB.getId());
EXPECT_EQ(artists.results[3], artistC.getId());
}
}
} // namespace lms::db::tests
+80
View File
@@ -1121,4 +1121,84 @@ namespace lms::db::tests
EXPECT_EQ(releaseImage->getId(), image.getId());
}
}
TEST_F(DatabaseFixture, Release_sortDateAdded)
{
ScopedRelease releaseA{ session, "relA" };
ScopedRelease releaseB{ session, "relB" };
ScopedRelease releaseC{ session, "relC" };
ScopedRelease releaseD{ session, "relD" };
ScopedTrack trackA1{ session };
ScopedTrack trackB1{ session };
ScopedTrack trackC1{ session };
ScopedTrack trackD1{ session };
ScopedTrack trackA2{ session };
{
auto transaction{ session.createWriteTransaction() };
trackA1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2 });
trackB1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 1 });
trackD1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2, 15, 36, 24 });
trackD1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 3 });
trackA2.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 4 });
trackA1.get().modify()->setRelease(releaseA.get());
trackA2.get().modify()->setRelease(releaseA.get());
trackB1.get().modify()->setRelease(releaseB.get());
trackC1.get().modify()->setRelease(releaseC.get());
trackD1.get().modify()->setRelease(releaseD.get());
}
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setSortMethod(ReleaseSortMethod::AddedDesc)) };
ASSERT_EQ(releases.results.size(), 4);
EXPECT_EQ(releases.results[0], releaseA.getId());
EXPECT_EQ(releases.results[1], releaseD.getId());
EXPECT_EQ(releases.results[2], releaseB.getId());
EXPECT_EQ(releases.results[3], releaseC.getId());
}
}
TEST_F(DatabaseFixture, Release_sortLastWritten)
{
ScopedRelease releaseA{ session, "relA" };
ScopedRelease releaseB{ session, "relB" };
ScopedRelease releaseC{ session, "relC" };
ScopedRelease releaseD{ session, "relD" };
ScopedTrack trackA1{ session };
ScopedTrack trackB1{ session };
ScopedTrack trackC1{ session };
ScopedTrack trackD1{ session };
ScopedTrack trackA2{ session };
{
auto transaction{ session.createWriteTransaction() };
trackA1.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 } });
trackB1.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 1 } });
trackD1.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 }, Wt::WTime{ 15, 36, 24 } });
trackD1.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 3 } });
trackA2.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 4 } });
trackA1.get().modify()->setRelease(releaseA.get());
trackA2.get().modify()->setRelease(releaseA.get());
trackB1.get().modify()->setRelease(releaseB.get());
trackC1.get().modify()->setRelease(releaseC.get());
trackD1.get().modify()->setRelease(releaseD.get());
}
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setSortMethod(ReleaseSortMethod::LastWrittenDesc)) };
ASSERT_EQ(releases.results.size(), 4);
EXPECT_EQ(releases.results[0], releaseA.getId());
EXPECT_EQ(releases.results[1], releaseD.getId());
EXPECT_EQ(releases.results[2], releaseB.getId());
EXPECT_EQ(releases.results[3], releaseC.getId());
}
}
} // namespace lms::db::tests
+50
View File
@@ -377,4 +377,54 @@ namespace lms::db::tests
EXPECT_EQ(track->getComment(), "MyComment");
}
}
TEST_F(DatabaseFixture, Track_sortDateAdded)
{
ScopedTrack track1{ session };
ScopedTrack track2{ session };
ScopedTrack track3{ session };
ScopedTrack track4{ session };
{
auto transaction{ session.createWriteTransaction() };
track1.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2 });
track2.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 1 });
track4.get().modify()->setAddedTime(core::PartialDateTime{ 2021, 1, 2, 15, 36, 24 });
}
{
auto transaction{ session.createReadTransaction() };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setSortMethod(TrackSortMethod::AddedDesc)) };
ASSERT_EQ(tracks.results.size(), 4);
EXPECT_EQ(tracks.results[0], track4.getId());
EXPECT_EQ(tracks.results[1], track1.getId());
EXPECT_EQ(tracks.results[2], track2.getId());
EXPECT_EQ(tracks.results[3], track3.getId());
}
}
TEST_F(DatabaseFixture, Track_sortLastWritten)
{
ScopedTrack track1{ session };
ScopedTrack track2{ session };
ScopedTrack track3{ session };
ScopedTrack track4{ session };
{
auto transaction{ session.createWriteTransaction() };
track1.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 } });
track2.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 1 } });
track4.get().modify()->setLastWriteTime(Wt::WDateTime{ Wt::WDate{ 2021, 1, 2 }, Wt::WTime{ 15, 36, 24 } });
}
{
auto transaction{ session.createReadTransaction() };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setSortMethod(TrackSortMethod::LastWrittenDesc)) };
ASSERT_EQ(tracks.results.size(), 4);
EXPECT_EQ(tracks.results[0], track4.getId());
EXPECT_EQ(tracks.results[1], track1.getId());
EXPECT_EQ(tracks.results[2], track2.getId());
EXPECT_EQ(tracks.results[3], track3.getId());
}
}
} // namespace lms::db::tests
@@ -124,7 +124,7 @@ namespace lms::api::subsonic
else if (type == "newest")
{
Release::FindParameters params;
params.setSortMethod(ReleaseSortMethod::LastWritten);
params.setSortMethod(ReleaseSortMethod::AddedDesc);
params.setRange(range);
params.setMediaLibrary(mediaLibraryId);
+1 -1
View File
@@ -99,7 +99,7 @@ namespace lms::ui
params.setKeywords(getSearchKeywords());
params.setMediaLibrary(filters.getMediaLibrary());
params.setLinkType(_linkType);
params.setSortMethod(ArtistSortMethod::LastWritten);
params.setSortMethod(ArtistSortMethod::AddedDesc);
params.setRange(range);
{
+1 -1
View File
@@ -92,7 +92,7 @@ namespace lms::ui
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setSortMethod(ReleaseSortMethod::LastWritten);
params.setSortMethod(ReleaseSortMethod::AddedDesc);
params.setRange(range);
{
+1 -1
View File
@@ -93,7 +93,7 @@ namespace lms::ui
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setSortMethod(TrackSortMethod::LastWritten);
params.setSortMethod(TrackSortMethod::AddedDesc);
params.setRange(range);
{