Optimized get most recent listen query for release

This commit is contained in:
emeric
2026-06-18 21:35:11 +02:00
parent 7b0039ab85
commit df8f8377c6
4 changed files with 92 additions and 14 deletions
+28 -3
View File
@@ -462,12 +462,25 @@ namespace lms::db
.bind(releaseId));
}
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId)
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ReleaseId releaseId)
{
session.checkReadTransaction();
// TODO not pending remove?
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l").join("track t ON l.track_id = t.id").where("t.release_id = ?").bind(releaseId).where("l.user_id = ?").bind(userId).where("l.backend = ?").bind(backend).orderBy("l.date_time DESC").limit(1));
// clang-format off
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l")
.join("user u ON u.id = l.user_id")
.join("track t ON l.track_id = t.id")
.where("t.release_id = ?").bind(releaseId)
.where("l.user_id = ?").bind(userId)
.where("l.backend = u.scrobbling_backend")
.orderBy("l.date_time DESC")
.limit(1)
};
// clang-format on
return utils::fetchQuerySingleResult(query);
}
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, TrackId trackId)
@@ -475,6 +488,18 @@ namespace lms::db
session.checkReadTransaction();
// TODO not pending remove?
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l").join("user u ON u.id = l.user_id").where("l.track_id = ?").bind(trackId).where("l.user_id = ?").bind(userId).where("l.backend = u.scrobbling_backend").orderBy("l.date_time DESC").limit(1));
// clang-format off
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l")
.join("user u ON u.id = l.user_id")
.where("l.track_id = ?").bind(trackId)
.where("l.user_id = ?").bind(userId)
.where("l.backend = u.scrobbling_backend")
.orderBy("l.date_time DESC")
.limit(1)
};
// clang-format on
return utils::fetchQuerySingleResult(query);
}
} // namespace lms::db
@@ -150,8 +150,8 @@ namespace lms::db
static std::size_t getCount(Session& session, UserId userId, TrackId trackId); // for the current backend
static std::size_t getCount(Session& session, UserId userId, ReleaseId trackId); // for the current backend
static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId);
static pointer getMostRecentListen(Session& session, UserId userId, TrackId trackId); // uses current scrobbling backend
static pointer getMostRecentListen(Session& session, UserId userId, ReleaseId releaseId); // uses current scrobbling backend
static pointer getMostRecentListen(Session& session, UserId userId, TrackId trackId); // uses current scrobbling backend
SyncState getSyncState() const { return _syncState; }
ObjectPtr<User> getUser() const { return _user; }
+61 -4
View File
@@ -1207,7 +1207,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto listen{ Listen::getMostRecentListen(session, user->getId(), ScrobblingBackend::Internal, release.getId()) };
const auto listen{ Listen::getMostRecentListen(session, user->getId(), release.getId()) };
EXPECT_FALSE(listen);
}
@@ -1217,7 +1217,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto listen{ Listen::getMostRecentListen(session, user->getId(), ScrobblingBackend::Internal, release.getId()) };
const auto listen{ Listen::getMostRecentListen(session, user->getId(), release.getId()) };
EXPECT_TRUE(listen);
EXPECT_EQ(listen->getDateTime(), dateTime1);
}
@@ -1228,7 +1228,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto listen{ Listen::getMostRecentListen(session, user->getId(), ScrobblingBackend::Internal, release.getId()) };
const auto listen{ Listen::getMostRecentListen(session, user->getId(), release.getId()) };
EXPECT_TRUE(listen);
EXPECT_EQ(listen->getDateTime(), dateTime1);
}
@@ -1239,12 +1239,69 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto listen{ Listen::getMostRecentListen(session, user->getId(), ScrobblingBackend::Internal, release.getId()) };
const auto listen{ Listen::getMostRecentListen(session, user->getId(), release.getId()) };
EXPECT_TRUE(listen);
EXPECT_EQ(listen->getDateTime(), dateTime3);
}
}
TEST_F(DatabaseFixture, Listen_getMostRecentRelease_byUserBackend)
{
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
ScopedRelease release{ session, "MyRelease" };
{
auto transaction{ session.createWriteTransaction() };
track.get().modify()->setRelease(release.get());
}
{
auto transaction{ session.createReadTransaction() };
EXPECT_FALSE(Listen::getMostRecentListen(session, user->getId(), release.getId()));
}
const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
{
auto transaction{ session.createReadTransaction() };
const auto listen{ Listen::getMostRecentListen(session, user->getId(), release.getId()) };
ASSERT_TRUE(listen);
EXPECT_EQ(listen->getDateTime(), dateTime1);
}
const Wt::WDateTime dateTime2{ Wt::WDate{ 1999, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen2{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime2 };
{
auto transaction{ session.createReadTransaction() };
const auto listen{ Listen::getMostRecentListen(session, user->getId(), release.getId()) };
ASSERT_TRUE(listen);
EXPECT_EQ(listen->getDateTime(), dateTime1);
}
const Wt::WDateTime dateTime3{ Wt::WDate{ 2001, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen3{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime3 };
{
auto transaction{ session.createReadTransaction() };
const auto listen{ Listen::getMostRecentListen(session, user->getId(), release.getId()) };
ASSERT_TRUE(listen);
EXPECT_EQ(listen->getDateTime(), dateTime3);
}
{
auto transaction{ session.createWriteTransaction() };
user.get().modify()->setScrobblingBackend(ScrobblingBackend::ListenBrainz);
}
{
auto transaction{ session.createReadTransaction() };
EXPECT_FALSE(Listen::getMostRecentListen(session, user->getId(), release.getId()));
}
}
TEST_F(DatabaseFixture, Listen_getRecentReleases_multi)
{
ScopedTrack track1{ session };
@@ -223,14 +223,10 @@ namespace lms::scrobbling
Wt::WDateTime ScrobblingService::getLastListenDateTime(db::UserId userId, db::ReleaseId releaseId)
{
const auto backend{ getUserBackend(userId) };
if (!backend)
return {};
Session& session{ _db.getTLSSession() };
auto transaction{ session.createReadTransaction() };
const db::Listen::pointer listen{ db::Listen::getMostRecentListen(session, userId, *backend, releaseId) };
const db::Listen::pointer listen{ db::Listen::getMostRecentListen(session, userId, releaseId) };
return listen ? listen->getDateTime() : Wt::WDateTime{};
}