diff --git a/src/libs/core/bench/CMakeLists.txt b/src/libs/core/bench/CMakeLists.txt
index 4ab4c319..7c07b875 100644
--- a/src/libs/core/bench/CMakeLists.txt
+++ b/src/libs/core/bench/CMakeLists.txt
@@ -2,6 +2,7 @@
add_executable(bench-core
Core.cpp
TraceLoggerBench.cpp
+ UUIDBench.cpp
)
target_link_libraries(bench-core PRIVATE
diff --git a/src/libs/core/bench/UUIDBench.cpp b/src/libs/core/bench/UUIDBench.cpp
new file mode 100644
index 00000000..1f22f93b
--- /dev/null
+++ b/src/libs/core/bench/UUIDBench.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2026 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#include
+
+#include "core/UUID.hpp"
+
+namespace lms::core::benchs
+{
+ static void BM_UUID_fromString(benchmark::State& state)
+ {
+ for (auto _ : state)
+ benchmark::DoNotOptimize(UUID::fromString("3f51c839-bee2-4e9d-a7b7-0693e45178fc"));
+ }
+
+ static void BM_UUID_fromString_invalid(benchmark::State& state)
+ {
+ for (auto _ : state)
+ benchmark::DoNotOptimize(UUID::fromString("not-a-valid-uuid-string-at-all-xx"));
+ }
+
+ static void BM_UUID_toString(benchmark::State& state)
+ {
+ const UUID uuid{ *UUID::fromString("3f51c839-bee2-4e9d-a7b7-0693e45178fc") };
+ for (auto _ : state)
+ benchmark::DoNotOptimize(uuid.toString());
+ }
+
+ static void BM_UUID_generate(benchmark::State& state)
+ {
+ for (auto _ : state)
+ benchmark::DoNotOptimize(UUID::generate());
+ }
+
+ BENCHMARK(BM_UUID_fromString);
+ BENCHMARK(BM_UUID_fromString_invalid);
+ BENCHMARK(BM_UUID_toString);
+ BENCHMARK(BM_UUID_generate);
+} // namespace lms::core::benchs
diff --git a/src/libs/core/impl/UUID.cpp b/src/libs/core/impl/UUID.cpp
index 756bcb1a..aafe5e4a 100644
--- a/src/libs/core/impl/UUID.cpp
+++ b/src/libs/core/impl/UUID.cpp
@@ -19,72 +19,93 @@
#include "core/UUID.hpp"
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
#include "core/Random.hpp"
-#include "core/String.hpp"
namespace lms::core
{
namespace stringUtils
{
template<>
- std::optional
- readAs(std::string_view str)
+ std::optional readAs(std::string_view str)
{
return UUID::fromString(str);
}
} // namespace stringUtils
+
namespace
{
- bool stringIsUUID(std::string_view str)
- {
- static const std::regex re{ R"([0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12})" };
+ // Each entry is the str index of the high hex char for that UUID byte
+ constexpr std::array byteOffsets{
+ 0, 2, 4, 6, // group 1 (4 bytes, positions 0-7)
+ 9, 11, // group 2 (2 bytes, positions 9-12)
+ 14, 16, // group 3 (2 bytes, positions 14-17)
+ 19, 21, // group 4 (2 bytes, positions 19-22)
+ 24, 26, 28, 30, 32, 34 // group 5 (6 bytes, positions 24-35)
+ };
- return std::regex_match(std::cbegin(str), std::cend(str), re);
+ bool parseUUID(std::string_view str, std::array& out)
+ {
+ if (str.size() != 36 || str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-')
+ return false;
+
+ for (std::size_t i{}; i < 16; ++i)
+ {
+ unsigned int byte{};
+ const char* begin{ str.data() + byteOffsets[i] };
+ const auto [ptr, ec]{ std::from_chars(begin, begin + 2, byte, 16) };
+ if (ec != std::errc{} || ptr != begin + 2)
+ return false;
+ out[i] = static_cast(byte);
+ }
+ return true;
}
} // namespace
- UUID::UUID(std::string_view str)
- : _value{ stringUtils::stringToLower(str) }
+ UUID::UUID(std::array bytes) noexcept
+ : _bytes{ bytes }
{
}
std::optional UUID::fromString(std::string_view str)
{
- if (!stringIsUUID(str))
+ std::array bytes{};
+ if (!parseUUID(str, bytes))
return std::nullopt;
+ return UUID{ bytes };
+ }
- return UUID{ str };
+ UUID UUID::fromBytes(std::span bytes) noexcept
+ {
+ std::array arr{};
+ std::copy(bytes.begin(), bytes.end(), arr.begin());
+ return UUID{ arr };
+ }
+
+ std::string UUID::toString() const
+ {
+ static constexpr char hex[]{ "0123456789abcdef" };
+ std::string s(36, '-');
+ for (std::size_t i{}; i < 16; ++i)
+ {
+ const auto b{ std::to_integer(_bytes[i]) };
+ s[byteOffsets[i]] = hex[b >> 4];
+ s[byteOffsets[i] + 1] = hex[b & 0x0F];
+ }
+ return s;
}
UUID UUID::generate()
{
- // Form is "123e4567-e89b-12d3-a456-426614174000"
- // TODO: store 128 bits and only convert to string when necessary
-
- std::ostringstream oss;
-
- auto concatRandomBytes{ [](std::ostream& os, std::size_t byteCount) {
- for (std::size_t i{}; i < byteCount; ++i)
- os << std::hex << std::setfill('0') << std::setw(2) << static_cast(random::getRandom(0, 255));
- } };
-
- concatRandomBytes(oss, 4);
- oss << "-";
- concatRandomBytes(oss, 2);
- oss << "-";
- concatRandomBytes(oss, 2);
- oss << "-";
- concatRandomBytes(oss, 2);
- oss << "-";
- concatRandomBytes(oss, 6);
-
- const auto uuid{ fromString(oss.str()) };
- assert(uuid);
- return uuid.value();
+ std::uniform_int_distribution dist{ 0, 255 };
+ auto& rng{ random::getRandGenerator() };
+ std::array bytes{};
+ for (auto& b : bytes)
+ b = static_cast(dist(rng));
+ return UUID{ bytes };
}
-} // namespace lms::core
\ No newline at end of file
+} // namespace lms::core
diff --git a/src/libs/core/include/core/UUID.hpp b/src/libs/core/include/core/UUID.hpp
index 422bba75..c7367ebf 100644
--- a/src/libs/core/include/core/UUID.hpp
+++ b/src/libs/core/include/core/UUID.hpp
@@ -19,8 +19,11 @@
#pragma once
+#include
+#include
#include
#include
+#include
#include
#include
@@ -31,24 +34,28 @@ namespace lms::core
class UUID
{
public:
+ static constexpr std::size_t binarySize{ 16 };
+
+ UUID() noexcept = default;
static std::optional fromString(std::string_view str);
+ static UUID fromBytes(std::span bytes) noexcept;
static UUID generate();
- std::string_view getAsString() const { return _value; }
+ std::string toString() const;
+ std::span bytes() const noexcept { return _bytes; }
auto operator<=>(const UUID&) const = default;
private:
- UUID(std::string_view value);
- std::string _value;
+ explicit UUID(std::array bytes) noexcept;
+ std::array _bytes{};
};
} // namespace lms::core
namespace lms::core::stringUtils
{
template<>
- std::optional
- readAs(std::string_view str);
+ std::optional readAs(std::string_view str);
}
namespace std
@@ -56,9 +63,10 @@ namespace std
template<>
struct hash
{
- size_t operator()(const lms::core::UUID& str) const
+ size_t operator()(const lms::core::UUID& uuid) const noexcept
{
- return hash{}(str.getAsString());
+ const auto& b{ uuid.bytes() };
+ return hash{}({ static_cast(static_cast(b.data())), b.size() });
}
};
} // namespace std
diff --git a/src/libs/core/test/UUID.cpp b/src/libs/core/test/UUID.cpp
index 9dad6f09..18d8b4d6 100644
--- a/src/libs/core/test/UUID.cpp
+++ b/src/libs/core/test/UUID.cpp
@@ -17,10 +17,7 @@
* along with LMS. If not, see .
*/
-#include
-#include
-#include
-#include
+#include
#include
@@ -28,6 +25,19 @@
namespace lms::core
{
+ TEST(UUID, fromString_invalid)
+ {
+ EXPECT_FALSE(UUID::fromString(""));
+ EXPECT_FALSE(UUID::fromString("not-a-uuid"));
+ EXPECT_FALSE(UUID::fromString("3f51c839-bee2-4e9d-a7b7-0693e45178f")); // too short
+ EXPECT_FALSE(UUID::fromString("3f51c839-bee2-4e9d-a7b7-0693e45178fcc")); // too long
+ EXPECT_FALSE(UUID::fromString("3f51c839-bee2-4e9d-a7b7_0693e45178fc")); // wrong separator position 23
+ EXPECT_FALSE(UUID::fromString("3f51c839-bee2-4e9d-a7b7-0693e45178gz")); // invalid hex char 'g','z'
+ EXPECT_FALSE(UUID::fromString("3f51c839Xbee2-4e9d-a7b7-0693e45178fc")); // dash replaced at position 8
+ EXPECT_FALSE(UUID::fromString("3f51c839-bee2X4e9d-a7b7-0693e45178fc")); // dash replaced at position 13
+ EXPECT_FALSE(UUID::fromString("3f51c839-bee2-4e9dXa7b7-0693e45178fc")); // dash replaced at position 18
+ }
+
TEST(UUID, caseInsensitive)
{
const std::optional uuid1{ UUID::fromString("3f51c839-bee2-4e9d-a7b7-0693e45178fc") };
@@ -37,4 +47,51 @@ namespace lms::core
EXPECT_TRUE(uuid1 >= uuid2);
EXPECT_TRUE(uuid1 <= uuid2);
}
+
+ TEST(UUID, toString_roundTrip)
+ {
+ const std::string str{ "3f51c839-bee2-4e9d-a7b7-0693e45178fc" };
+ const std::optional uuid{ UUID::fromString(str) };
+
+ ASSERT_TRUE(uuid);
+ EXPECT_EQ(uuid->toString(), str);
+ }
+
+ TEST(UUID, toString_lowercase)
+ {
+ const std::optional uuid{ UUID::fromString("3F51C839-BEE2-4E9D-A7B7-0693E45178FC") };
+
+ ASSERT_TRUE(uuid);
+ EXPECT_EQ(uuid->toString(), "3f51c839-bee2-4e9d-a7b7-0693e45178fc");
+ }
+
+ TEST(UUID, fromBytes_roundTrip)
+ {
+ const std::optional uuid{ UUID::fromString("550e8400-e29b-41d4-a716-446655440000") };
+ ASSERT_TRUE(uuid);
+
+ const UUID fromB{ UUID::fromBytes(uuid->bytes()) };
+ EXPECT_EQ(fromB, *uuid);
+ EXPECT_EQ(fromB.toString(), "550e8400-e29b-41d4-a716-446655440000");
+ }
+
+ TEST(UUID, bytes_size)
+ {
+ const std::optional uuid{ UUID::fromString("3f51c839-bee2-4e9d-a7b7-0693e45178fc") };
+ ASSERT_TRUE(uuid);
+ EXPECT_EQ(uuid->bytes().size(), 16U);
+ }
+
+ TEST(UUID, generate_validString)
+ {
+ const UUID uuid{ UUID::generate() };
+ const std::string s{ uuid.toString() };
+
+ ASSERT_EQ(s.size(), 36U);
+ EXPECT_EQ(s[8], '-');
+ EXPECT_EQ(s[13], '-');
+ EXPECT_EQ(s[18], '-');
+ EXPECT_EQ(s[23], '-');
+ EXPECT_TRUE(UUID::fromString(s).has_value());
+ }
} // namespace lms::core
\ No newline at end of file
diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp
index e7b2e54a..93e4f5f8 100644
--- a/src/libs/database/impl/Migration.cpp
+++ b/src/libs/database/impl/Migration.cpp
@@ -35,7 +35,7 @@ namespace lms::db
{
namespace
{
- static constexpr Version LMS_DATABASE_VERSION{ 106 };
+ static constexpr Version LMS_DATABASE_VERSION{ 107 };
}
VersionInfo::VersionInfo()
@@ -1736,6 +1736,44 @@ FROM track)");
utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE "user" ADD COLUMN "lastfm_session_key" TEXT NOT NULL DEFAULT '')");
}
+ void migrateFromV106(Session& session)
+ {
+ dropIndexes(session);
+
+ // Convert the 5 MBID TEXT columns to BLOB (16 raw bytes)
+ // unhex() returns NULL for non-hex input, so malformed values become NULL
+
+ // artist.mbid
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE artist ADD COLUMN mbid_new BLOB)");
+ utils::executeCommand(*session.getDboSession(), R"(UPDATE artist SET mbid_new = CASE WHEN mbid != '' THEN unhex(replace(mbid, '-', '')) ELSE NULL END)");
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE artist DROP COLUMN mbid)");
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE artist RENAME COLUMN mbid_new TO mbid)");
+
+ // release.mbid
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE release ADD COLUMN mbid_new BLOB)");
+ utils::executeCommand(*session.getDboSession(), R"(UPDATE release SET mbid_new = CASE WHEN mbid != '' THEN unhex(replace(mbid, '-', '')) ELSE NULL END)");
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE release DROP COLUMN mbid)");
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE release RENAME COLUMN mbid_new TO mbid)");
+
+ // release.group_mbid
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE release ADD COLUMN group_mbid_new BLOB)");
+ utils::executeCommand(*session.getDboSession(), R"(UPDATE release SET group_mbid_new = CASE WHEN group_mbid != '' THEN unhex(replace(group_mbid, '-', '')) ELSE NULL END)");
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE release DROP COLUMN group_mbid)");
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE release RENAME COLUMN group_mbid_new TO group_mbid)");
+
+ // track.mbid
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE track ADD COLUMN mbid_new BLOB)");
+ utils::executeCommand(*session.getDboSession(), R"(UPDATE track SET mbid_new = CASE WHEN mbid != '' THEN unhex(replace(mbid, '-', '')) ELSE NULL END)");
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE track DROP COLUMN mbid)");
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE track RENAME COLUMN mbid_new TO mbid)");
+
+ // track.recording_mbid
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE track ADD COLUMN recording_mbid_new BLOB)");
+ utils::executeCommand(*session.getDboSession(), R"(UPDATE track SET recording_mbid_new = CASE WHEN recording_mbid != '' THEN unhex(replace(recording_mbid, '-', '')) ELSE NULL END)");
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE track DROP COLUMN recording_mbid)");
+ utils::executeCommand(*session.getDboSession(), R"(ALTER TABLE track RENAME COLUMN recording_mbid_new TO recording_mbid)");
+ }
+
bool doDbMigration(Session& session)
{
constexpr std::string_view outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" };
@@ -1818,6 +1856,7 @@ FROM track)");
{ 103, migrateFromV103 },
{ 104, migrateFromV104 },
{ 105, migrateFromV105 },
+ { 106, migrateFromV106 },
};
bool migrationPerformed{};
diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp
index f1c0371f..df51253e 100644
--- a/src/libs/database/impl/Session.cpp
+++ b/src/libs/database/impl/Session.cpp
@@ -66,6 +66,7 @@
#include "traits/ImageHashTypeTraits.hpp"
#include "traits/PartialDateTimeTraits.hpp"
#include "traits/PathTraits.hpp"
+#include "traits/UUIDTraits.hpp"
namespace lms::db
{
diff --git a/src/libs/database/impl/objects/Artist.cpp b/src/libs/database/impl/objects/Artist.cpp
index 6e7cf657..d064e7fc 100644
--- a/src/libs/database/impl/objects/Artist.cpp
+++ b/src/libs/database/impl/objects/Artist.cpp
@@ -35,6 +35,7 @@
#include "objects/detail/Types.hpp"
#include "traits/IdTypeTraits.hpp"
#include "traits/StringViewTraits.hpp"
+#include "traits/UUIDTraits.hpp"
DBO_INSTANTIATE_TEMPLATES(lms::db::Artist)
@@ -214,7 +215,7 @@ namespace lms::db
} // namespace
Artist::Artist(const std::string& name, const std::optional& mbid)
- : _mbid{ mbid ? mbid->getAsString() : "" }
+ : _mbid{ mbid }
{
setName(name);
}
@@ -277,7 +278,7 @@ namespace lms::db
Artist::pointer Artist::find(Session& session, const core::UUID& mbid)
{
session.checkReadTransaction();
- return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT a FROM artist a").where("a.mbid = ?").bind(std::string{ mbid.getAsString() }));
+ return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT a FROM artist a").where("a.mbid = ?").bind(mbid));
}
Artist::pointer Artist::find(Session& session, ArtistId id)
@@ -386,17 +387,6 @@ AND NOT EXISTS (
utils::executeCommand(*session.getDboSession(), "UPDATE artist SET preferred_artwork_id = NULL WHERE id = ?", artistId);
}
- std::optional Artist::getMBID() const
- {
- return core::UUID::fromString(_mbid);
- }
-
- bool Artist::hasMBID() const
- {
- // TODO optim this
- return getMBID().has_value();
- }
-
ObjectPtr Artist::getPreferredArtwork() const
{
return ObjectPtr{ _preferredArtwork };
diff --git a/src/libs/database/impl/objects/ArtistInfo.cpp b/src/libs/database/impl/objects/ArtistInfo.cpp
index b7acd5d4..736acbb2 100644
--- a/src/libs/database/impl/objects/ArtistInfo.cpp
+++ b/src/libs/database/impl/objects/ArtistInfo.cpp
@@ -112,13 +112,13 @@ namespace lms::db
query.where("a_i.mbid_matched = FALSE");
if (!allowArtistMBIDFallback)
{
- query.where("a.mbid <> ''");
+ query.where("a.mbid IS NOT NULL");
}
else
{
query.where(R"(
- (a.mbid <> '' AND EXISTS (SELECT 1 FROM artist a2 WHERE a2.name = a.name AND a2.mbid <> '' AND a2.mbid <> a.mbid))
- OR (a.mbid = '' AND (SELECT COUNT(*) FROM artist a2 WHERE a2.name = a.name AND a2.mbid <> '') = 1))");
+ (a.mbid IS NOT NULL AND EXISTS (SELECT 1 FROM artist a2 WHERE a2.name = a.name AND a2.mbid IS NOT NULL AND a2.mbid <> a.mbid))
+ OR (a.mbid IS NULL AND (SELECT COUNT(*) FROM artist a2 WHERE a2.name = a.name AND a2.mbid IS NOT NULL) = 1))");
}
utils::applyRange(query, range);
diff --git a/src/libs/database/impl/objects/Release.cpp b/src/libs/database/impl/objects/Release.cpp
index 1747fe75..8117f978 100644
--- a/src/libs/database/impl/objects/Release.cpp
+++ b/src/libs/database/impl/objects/Release.cpp
@@ -46,6 +46,7 @@
#include "traits/IdTypeTraits.hpp"
#include "traits/PartialDateTimeTraits.hpp"
#include "traits/StringViewTraits.hpp"
+#include "traits/UUIDTraits.hpp"
DBO_INSTANTIATE_TEMPLATES(lms::db::Country)
DBO_INSTANTIATE_TEMPLATES(lms::db::Label)
@@ -218,7 +219,7 @@ namespace lms::db
query.where("t.codec = ?").bind(detail::getDbCodec(params.filters.codec.value()));
if (params.releaseGroupMBID)
- query.where("group_mbid = ?").bind(params.releaseGroupMBID->getAsString());
+ query.where("group_mbid = ?").bind(*params.releaseGroupMBID);
switch (params.sortMethod)
{
@@ -454,7 +455,7 @@ namespace lms::db
Release::Release(const std::string& name, const std::optional& MBID)
: _name{ std::string(name, 0, _maxNameLength) }
- , _MBID{ MBID ? MBID->getAsString() : "" }
+ , _MBID{ MBID }
{
}
@@ -467,7 +468,7 @@ namespace lms::db
{
session.checkReadTransaction();
- return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT r from release r").where("r.mbid = ?").bind(mbid.getAsString()));
+ return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT r from release r").where("r.mbid = ?").bind(mbid));
}
Release::pointer Release::find(Session& session, ReleaseId id)
diff --git a/src/libs/database/impl/objects/ReleaseArtistLink.cpp b/src/libs/database/impl/objects/ReleaseArtistLink.cpp
index 6c508c4c..c6eeeb7a 100644
--- a/src/libs/database/impl/objects/ReleaseArtistLink.cpp
+++ b/src/libs/database/impl/objects/ReleaseArtistLink.cpp
@@ -123,13 +123,13 @@ namespace lms::db
query.where("r_a_l.artist_mbid_matched = FALSE");
if (!allowArtistMBIDFallback)
{
- query.where("a.mbid <> ''");
+ query.where("a.mbid IS NOT NULL");
}
else
{
query.where(R"(
- (a.mbid <> '' AND EXISTS (SELECT 1 FROM artist a2 WHERE a2.name = a.name AND a2.mbid <> '' AND a2.mbid <> a.mbid))
- OR (a.mbid = '' AND (SELECT COUNT(*) FROM artist a2 WHERE a2.name = a.name AND a2.mbid <> '') = 1))");
+ (a.mbid IS NOT NULL AND EXISTS (SELECT 1 FROM artist a2 WHERE a2.name = a.name AND a2.mbid IS NOT NULL AND a2.mbid <> a.mbid))
+ OR (a.mbid IS NULL AND (SELECT COUNT(*) FROM artist a2 WHERE a2.name = a.name AND a2.mbid IS NOT NULL) = 1))");
}
utils::applyRange(query, range);
diff --git a/src/libs/database/impl/objects/Track.cpp b/src/libs/database/impl/objects/Track.cpp
index 00aa93d5..ff8ad52d 100644
--- a/src/libs/database/impl/objects/Track.cpp
+++ b/src/libs/database/impl/objects/Track.cpp
@@ -46,6 +46,7 @@
#include "traits/PartialDateTimeTraits.hpp"
#include "traits/PathTraits.hpp"
#include "traits/StringViewTraits.hpp"
+#include "traits/UUIDTraits.hpp"
DBO_INSTANTIATE_TEMPLATES(lms::db::Track)
@@ -392,21 +393,21 @@ namespace lms::db
{
session.checkReadTransaction();
- return utils::fetchQueryResults(session.getDboSession()->query>("SELECT t from track t").where("t.mbid = ?").bind(mbid.getAsString()));
+ return utils::fetchQueryResults(session.getDboSession()->query>("SELECT t from track t").where("t.mbid = ?").bind(mbid));
}
std::vector Track::findByRecordingMBID(Session& session, const core::UUID& mbid)
{
session.checkReadTransaction();
- return utils::fetchQueryResults(session.getDboSession()->query>("SELECT t from track t").where("t.recording_mbid = ?").bind(mbid.getAsString()));
+ return utils::fetchQueryResults(session.getDboSession()->query>("SELECT t from track t").where("t.recording_mbid = ?").bind(mbid));
}
RangeResults Track::findIdsTrackMBIDDuplicates(Session& session, std::optional range)
{
session.checkReadTransaction();
- auto query{ session.getDboSession()->query("SELECT track.id FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid <> '' GROUP BY mbid HAVING COUNT (*) > 1)").orderBy("track.release_id,track.mbid") };
+ auto query{ session.getDboSession()->query("SELECT track.id FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid IS NOT NULL GROUP BY mbid HAVING COUNT (*) > 1)").orderBy("track.release_id,track.mbid") };
return utils::execRangeQuery(query, range);
}
diff --git a/src/libs/database/impl/objects/TrackArtistLink.cpp b/src/libs/database/impl/objects/TrackArtistLink.cpp
index 3366d6bc..8ad07317 100644
--- a/src/libs/database/impl/objects/TrackArtistLink.cpp
+++ b/src/libs/database/impl/objects/TrackArtistLink.cpp
@@ -165,13 +165,13 @@ namespace lms::db
query.where("t_a_l.artist_mbid_matched = FALSE");
if (!allowArtistMBIDFallback)
{
- query.where("a.mbid <> ''");
+ query.where("a.mbid IS NOT NULL");
}
else
{
query.where(R"(
- (a.mbid <> '' AND EXISTS (SELECT 1 FROM artist a2 WHERE a2.name = a.name AND a2.mbid <> '' AND a2.mbid <> a.mbid))
- OR (a.mbid = '' AND (SELECT COUNT(*) FROM artist a2 WHERE a2.name = a.name AND a2.mbid <> '') = 1))");
+ (a.mbid IS NOT NULL AND EXISTS (SELECT 1 FROM artist a2 WHERE a2.name = a.name AND a2.mbid IS NOT NULL AND a2.mbid <> a.mbid))
+ OR (a.mbid IS NULL AND (SELECT COUNT(*) FROM artist a2 WHERE a2.name = a.name AND a2.mbid IS NOT NULL) = 1))");
}
utils::applyRange(query, range);
diff --git a/src/libs/database/impl/traits/UUIDTraits.hpp b/src/libs/database/impl/traits/UUIDTraits.hpp
new file mode 100644
index 00000000..25d7b510
--- /dev/null
+++ b/src/libs/database/impl/traits/UUIDTraits.hpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2025 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "core/UUID.hpp"
+
+namespace Wt::Dbo
+{
+ template<>
+ struct sql_value_traits
+ {
+ static constexpr bool specialized{ true };
+ using UnderlyingType = std::vector;
+
+ static std::string type(SqlConnection* conn, int size)
+ {
+ return sql_value_traits::type(conn, size);
+ }
+
+ static void bind(const lms::core::UUID& v, SqlStatement* statement, int column, int size)
+ {
+ constexpr auto binarySize{ lms::core::UUID::binarySize };
+ const auto bytes{ v.bytes() };
+ UnderlyingType blob(binarySize);
+ std::memcpy(blob.data(), bytes.data(), binarySize);
+ sql_value_traits::bind(blob, statement, column, size);
+ }
+
+ static bool read(lms::core::UUID& v, SqlStatement* statement, int column, int size)
+ {
+ constexpr auto binarySize{ lms::core::UUID::binarySize };
+ UnderlyingType buf;
+ if (!sql_value_traits::read(buf, statement, column, size) || buf.size() != binarySize)
+ return false;
+
+ v = lms::core::UUID::fromBytes(std::span{ reinterpret_cast(buf.data()), binarySize });
+ return true;
+ }
+ };
+} // namespace Wt::Dbo
diff --git a/src/libs/database/include/database/objects/Artist.hpp b/src/libs/database/include/database/objects/Artist.hpp
index 1d3adbda..8786c15f 100644
--- a/src/libs/database/include/database/objects/Artist.hpp
+++ b/src/libs/database/include/database/objects/Artist.hpp
@@ -141,8 +141,8 @@ namespace lms::db
// Accessors
const std::string& getName() const { return _name; }
const std::string& getSortName() const { return _sortName; }
- std::optional getMBID() const;
- bool hasMBID() const;
+ std::optional getMBID() const { return _mbid; }
+ bool hasMBID() const { return _mbid.has_value(); }
ObjectPtr getPreferredArtwork() const;
ArtworkId getPreferredArtworkId() const;
@@ -152,7 +152,7 @@ namespace lms::db
std::vector>> getClusterGroups(std::span clusterTypeIds, std::size_t size) const;
void setName(std::string_view name);
- void setMBID(const std::optional& mbid) { _mbid = mbid ? mbid->getAsString() : ""; }
+ void setMBID(const std::optional& mbid) { _mbid = mbid; }
void setSortName(std::string_view sortName);
void setPreferredArtwork(ObjectPtr artwork);
@@ -174,7 +174,7 @@ namespace lms::db
std::string _name;
std::string _sortName;
- std::string _mbid; // Musicbrainz Identifier
+ std::optional _mbid;
Wt::Dbo::ptr _preferredArtwork;
};
diff --git a/src/libs/database/include/database/objects/Release.hpp b/src/libs/database/include/database/objects/Release.hpp
index 53eec131..95a0d1ae 100644
--- a/src/libs/database/include/database/objects/Release.hpp
+++ b/src/libs/database/include/database/objects/Release.hpp
@@ -298,8 +298,8 @@ namespace lms::db
// Accessors
std::string_view getName() const { return _name; }
std::string_view getSortName() const { return _sortName; }
- std::optional getMBID() const { return core::UUID::fromString(_MBID); }
- std::optional getGroupMBID() const { return core::UUID::fromString(_groupMBID); }
+ std::optional getMBID() const { return _MBID; }
+ std::optional getGroupMBID() const { return _groupMBID; }
std::optional getTotalDisc() const { return _totalDisc; } // the number of discs this release should have if complete
std::chrono::milliseconds getDuration() const;
Wt::WDateTime getAddedTime() const;
@@ -325,8 +325,8 @@ namespace lms::db
// Setters
void setName(std::string_view name) { _name = name; }
void setSortName(std::string_view sortName) { _sortName = sortName; }
- void setMBID(const std::optional& mbid) { _MBID = mbid ? mbid->getAsString() : ""; }
- void setGroupMBID(const std::optional& mbid) { _groupMBID = mbid ? mbid->getAsString() : ""; }
+ void setMBID(const std::optional& mbid) { _MBID = mbid; }
+ void setGroupMBID(const std::optional& mbid) { _groupMBID = mbid; }
void setTotalDisc(std::optional totalDisc) { _totalDisc = totalDisc; }
void setArtistDisplayName(std::string_view name) { _artistDisplayName = name; }
void clearArtistLinks();
@@ -382,8 +382,8 @@ namespace lms::db
std::string _name;
std::string _sortName;
- std::string _MBID;
- std::string _groupMBID;
+ std::optional _MBID;
+ std::optional _groupMBID;
std::optional _totalDisc{};
std::string _artistDisplayName;
bool _isCompilation{}; // See https://picard-docs.musicbrainz.org/en/appendices/tag_mapping.html#compilation-itunes-5
diff --git a/src/libs/database/include/database/objects/Track.hpp b/src/libs/database/include/database/objects/Track.hpp
index cc06c373..9be95a2a 100644
--- a/src/libs/database/include/database/objects/Track.hpp
+++ b/src/libs/database/include/database/objects/Track.hpp
@@ -258,8 +258,8 @@ namespace lms::db
void setName(std::string_view name);
void setDate(const core::PartialDateTime& date) { _date = date; }
void setOriginalDate(const core::PartialDateTime& date) { _originalDate = date; }
- void setTrackMBID(const std::optional& MBID) { _trackMBID = MBID ? MBID->getAsString() : ""; }
- void setRecordingMBID(const std::optional& MBID) { _recordingMBID = MBID ? MBID->getAsString() : ""; }
+ void setTrackMBID(const std::optional& MBID) { _trackMBID = MBID; }
+ void setRecordingMBID(const std::optional& MBID) { _recordingMBID = MBID; }
void setCopyright(std::string_view copyright);
void setCopyrightURL(std::string_view copyrightURL);
void setAdvisory(Advisory advisory) { _advisory = advisory; }
@@ -308,8 +308,8 @@ namespace lms::db
std::optional getOriginalYear() const;
const Wt::WDateTime& getLastWriteTime() const { return _fileLastWrite; }
bool hasLyrics() const;
- std::optional getTrackMBID() const { return core::UUID::fromString(_trackMBID); }
- std::optional getRecordingMBID() const { return core::UUID::fromString(_recordingMBID); }
+ std::optional getTrackMBID() const { return _trackMBID; }
+ std::optional getRecordingMBID() const { return _recordingMBID; }
std::string_view getCopyright() const;
std::string_view getCopyrightURL() const;
std::string_view getArtistDisplayName() const { return _artistDisplayName; }
@@ -413,8 +413,8 @@ namespace lms::db
std::string _name;
core::PartialDateTime _date;
core::PartialDateTime _originalDate;
- std::string _trackMBID;
- std::string _recordingMBID;
+ std::optional _trackMBID;
+ std::optional _recordingMBID;
std::string _copyright;
std::string _copyrightURL;
std::string _artistDisplayName;
diff --git a/src/libs/database/test/Migration.cpp b/src/libs/database/test/Migration.cpp
index 522e9097..82c4b00c 100644
--- a/src/libs/database/test/Migration.cpp
+++ b/src/libs/database/test/Migration.cpp
@@ -20,6 +20,7 @@
#include "Common.hpp"
#include "core/String.hpp"
+#include "core/UUID.hpp"
#include "database/objects/Artist.hpp"
#include "database/objects/ArtistInfo.hpp"
@@ -289,14 +290,14 @@ CREATE INDEX starred_release_user_scrobbler_idx ON starred_release(user_id,scrob
CREATE INDEX starred_track_user_scrobbler_idx ON starred_track(user_id,scrobbler);)" };
const std::string_view createDummyData{ R"(
--- Inserting artists
+-- Inserting artists (Artist A has a valid UUID MBID to verify round-trip through migration)
INSERT INTO artist (version, name, sort_name, mbid) VALUES
-(1, 'Artist A', 'Artist A', 'mbid_artist_a'),
+(1, 'Artist A', 'Artist A', '550e8400-e29b-41d4-a716-446655440000'),
(2, 'Artist B', 'Artist B', 'mbid_artist_b');
--- Inserting releases
+-- Inserting releases (Release X has a valid UUID MBID to verify round-trip through migration)
INSERT INTO release (version, name, mbid) VALUES
-(1, 'Release X', 'mbid_release_x'),
+(1, 'Release X', '6ba7b810-9dad-11d1-80b4-00c04fd430c8'),
(2, 'Release Y', 'mbid_release_y');
-- Inserting tracks without any associated artists or releases (Orphan Tracks)
@@ -381,6 +382,19 @@ VALUES
EXPECT_FALSE(TrackLyrics::find(session, TrackLyricsId{}));
EXPECT_FALSE(UIState::find(session, UIStateId{}));
EXPECT_FALSE(User::find(session, UserId{}));
+
+ // Verify UUID MBID round-trip through V107 migration (TEXT → BLOB)
+ const auto artistMBID{ core::UUID::fromString("550e8400-e29b-41d4-a716-446655440000") };
+ ASSERT_TRUE(artistMBID);
+ const auto artist{ Artist::find(session, *artistMBID) };
+ ASSERT_TRUE(artist);
+ EXPECT_EQ(artist->getMBID(), artistMBID);
+
+ const auto releaseMBID{ core::UUID::fromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") };
+ ASSERT_TRUE(releaseMBID);
+ const auto release{ Release::find(session, *releaseMBID) };
+ ASSERT_TRUE(release);
+ EXPECT_EQ(release->getMBID(), releaseMBID);
}
}
} // namespace lms::db::tests
\ No newline at end of file
diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbackTypes.cpp b/src/libs/services/feedback/impl/listenbrainz/FeedbackTypes.cpp
index 5d231141..89380df8 100644
--- a/src/libs/services/feedback/impl/listenbrainz/FeedbackTypes.cpp
+++ b/src/libs/services/feedback/impl/listenbrainz/FeedbackTypes.cpp
@@ -25,7 +25,7 @@ namespace lms::feedback::listenBrainz
{
std::ostream& operator<<(std::ostream& os, const Feedback& feedback)
{
- os << "created = '" << feedback.created.toString() << "', recording MBID = '" << feedback.recordingMBID.getAsString() << "', score = " << static_cast(feedback.score);
+ os << "created = '" << feedback.created.toString() << "', recording MBID = '" << feedback.recordingMBID.toString() << "', score = " << static_cast(feedback.score);
return os;
}
} // namespace lms::feedback::listenBrainz
diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp
index 0ba352a2..2818ae13 100644
--- a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp
+++ b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp
@@ -127,7 +127,7 @@ namespace lms::feedback::listenBrainz
request.message.addHeader("Authorization", "Token " + listenBrainzToken);
Wt::Json::Object root;
- root["recording_mbid"] = Wt::Json::Value{ std::string{ recordingMBID->getAsString() } };
+ root["recording_mbid"] = Wt::Json::Value{ recordingMBID->toString() };
root["score"] = Wt::Json::Value{ static_cast(type) };
request.message.addBodyText(Wt::Json::serialize(root));
diff --git a/src/libs/services/podcast/impl/steps/Utils.cpp b/src/libs/services/podcast/impl/steps/Utils.cpp
index f60adaaa..cdf9ae42 100644
--- a/src/libs/services/podcast/impl/steps/Utils.cpp
+++ b/src/libs/services/podcast/impl/steps/Utils.cpp
@@ -78,7 +78,7 @@ namespace lms::podcast::utils
std::string generateRandomFileName()
{
- return std::string{ core::UUID::generate().getAsString() };
+ return core::UUID::generate().toString();
}
void removeFile(const std::filesystem::path& filePath)
diff --git a/src/libs/services/recommendation/impl/audio-similarity/AudioSimilarityEngine.impl.hpp b/src/libs/services/recommendation/impl/audio-similarity/AudioSimilarityEngine.impl.hpp
index 92a28801..c3c869c7 100644
--- a/src/libs/services/recommendation/impl/audio-similarity/AudioSimilarityEngine.impl.hpp
+++ b/src/libs/services/recommendation/impl/audio-similarity/AudioSimilarityEngine.impl.hpp
@@ -620,7 +620,7 @@ namespace lms::recommendation
db::Artist::find(session, db::Artist::FindParameters{}, [&](const db::Artist::pointer& artist) {
const auto mbid{ artist->getMBID() };
// skip "Various Artists" to avoid false artist matches
- if (mbid && mbid->getAsString() == "89ad4ac3-39f7-470e-963a-56509c546377")
+ if (mbid && mbid->toString() == "89ad4ac3-39f7-470e-963a-56509c546377")
return;
std::unordered_set artistTrackIds;
diff --git a/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp b/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp
index 86540518..5e4476a8 100644
--- a/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp
+++ b/src/libs/services/recommendation/impl/clusters/ClustersEngine.cpp
@@ -144,7 +144,7 @@ namespace lms::recommendation
db::Artist::find(session, db::Artist::FindParameters{}, [&](const db::Artist::pointer& artist) {
const auto mbid{ artist->getMBID() };
// skip "Various Artists" to avoid false artist matches
- if (mbid && mbid->getAsString() == "89ad4ac3-39f7-470e-963a-56509c546377")
+ if (mbid && mbid->toString() == "89ad4ac3-39f7-470e-963a-56509c546377")
return;
std::unordered_set artistTrackIds;
diff --git a/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp b/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp
index 2a8ff7c7..83d036b6 100644
--- a/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp
+++ b/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp
@@ -46,7 +46,7 @@ namespace lms::scanner
{
os << "'" << artist->getName() << "'";
if (const auto mbid{ artist->getMBID() })
- os << " [" << mbid->getAsString() << "]";
+ os << " [" << mbid->toString() << "]";
return os;
}
diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp
index c5d9bf13..fec80a73 100644
--- a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp
+++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp
@@ -94,7 +94,7 @@ namespace lms::scanner
db::Image::pointer image;
// Find anywhere, since it is supposed to be unique!
- db::Image::find(session, db::Image::FindParameters{}.setFileStem(mbid.getAsString()), [&](const db::Image::pointer foundImg) {
+ db::Image::find(session, db::Image::FindParameters{}.setFileStem(mbid.toString()), [&](const db::Image::pointer foundImg) {
if (!image)
image = foundImg;
});
diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp
index 341366a7..749d041d 100644
--- a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp
+++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp
@@ -90,7 +90,7 @@ namespace lms::scanner
if (mbid)
{
// Find anywhere, since it is suppoed to be unique!
- db::Image::find(session, db::Image::FindParameters{}.setFileStem(mbid->getAsString()), [&](const db::Image::pointer& image) {
+ db::Image::find(session, db::Image::FindParameters{}.setFileStem(mbid->toString()), [&](const db::Image::pointer& image) {
if (!artwork)
artwork = db::Artwork::find(session, image->getId());
});
diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp
index 3b236cd7..8c3aafae 100644
--- a/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp
+++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp
@@ -50,7 +50,7 @@ namespace lms::scanner
const Track::pointer track{ Track::find(session, trackId) };
if (auto trackMBID{ track->getTrackMBID() })
{
- LMS_LOG(DBUPDATER, INFO, "Found duplicated track MBID [" << trackMBID->getAsString() << "], file: " << track->getAbsoluteFilePath().string() << " - " << track->getName());
+ LMS_LOG(DBUPDATER, INFO, "Found duplicated track MBID [" << trackMBID->toString() << "], file: " << track->getAbsoluteFilePath().string() << " - " << track->getName());
context.stats.duplicates.emplace_back(ScanDuplicate{ track->getId(), DuplicateReason::SameTrackMBID });
context.currentStepStats.processedElems++;
_progressCallback(context.currentStepStats);
diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListenTypes.cpp b/src/libs/services/scrobbling/impl/listenbrainz/ListenTypes.cpp
index 322ae5f0..d1092c54 100644
--- a/src/libs/services/scrobbling/impl/listenbrainz/ListenTypes.cpp
+++ b/src/libs/services/scrobbling/impl/listenbrainz/ListenTypes.cpp
@@ -31,9 +31,9 @@ namespace lms::scrobbling::listenBrainz
if (listen.trackNumber)
os << ", trackNumber = " << *listen.trackNumber;
if (listen.trackMBID)
- os << ", trackMBID = '" << listen.trackMBID->getAsString() << "'";
+ os << ", trackMBID = '" << listen.trackMBID->toString() << "'";
if (listen.recordingMBID)
- os << ", recordingMBID = '" << listen.recordingMBID->getAsString() << "'";
+ os << ", recordingMBID = '" << listen.recordingMBID->toString() << "'";
return os;
}
diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp
index 62da3092..ac271a80 100644
--- a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp
+++ b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp
@@ -89,9 +89,9 @@ namespace lms::scrobbling::listenBrainz
if (const auto release{ track->getRelease() })
{
if (auto MBID{ release->getMBID() })
- additionalInfo["release_mbid"] = Wt::Json::Value{ std::string{ MBID->getAsString() } };
+ additionalInfo["release_mbid"] = Wt::Json::Value{ MBID->toString() };
if (auto groupMBID{ release->getGroupMBID() })
- additionalInfo["release_group_mbid"] = Wt::Json::Value{ std::string{ groupMBID->getAsString() } };
+ additionalInfo["release_group_mbid"] = Wt::Json::Value{ groupMBID->toString() };
}
{
@@ -99,7 +99,7 @@ namespace lms::scrobbling::listenBrainz
for (const Artist& artist : artists)
{
if (artist.mbid)
- artistMBIDs.push_back(Wt::Json::Value{ std::string{ artist.mbid->getAsString() } });
+ artistMBIDs.push_back(Wt::Json::Value{ artist.mbid->toString() });
}
if (!artistMBIDs.empty())
@@ -107,10 +107,10 @@ namespace lms::scrobbling::listenBrainz
}
if (auto MBID{ track->getTrackMBID() })
- additionalInfo["track_mbid"] = Wt::Json::Value{ std::string{ MBID->getAsString() } };
+ additionalInfo["track_mbid"] = Wt::Json::Value{ MBID->toString() };
if (auto MBID{ track->getRecordingMBID() })
- additionalInfo["recording_mbid"] = Wt::Json::Value{ std::string{ MBID->getAsString() } };
+ additionalInfo["recording_mbid"] = Wt::Json::Value{ MBID->toString() };
if (const std::optional trackNumber{ track->getTrackNumber() })
additionalInfo["tracknumber"] = Wt::Json::Value{ static_cast(*trackNumber) };
diff --git a/src/libs/services/scrobbling/test/Listenbrainz.cpp b/src/libs/services/scrobbling/test/Listenbrainz.cpp
index 3b585d0d..8be3a0bc 100644
--- a/src/libs/services/scrobbling/test/Listenbrainz.cpp
+++ b/src/libs/services/scrobbling/test/Listenbrainz.cpp
@@ -60,18 +60,18 @@ namespace lms::scrobbling::listenBrainz::tests
EXPECT_EQ(result.listens[0].releaseName, "Petal");
EXPECT_EQ(result.listens[0].artistName, "Broke For Free");
ASSERT_TRUE(result.listens[0].recordingMBID.has_value());
- EXPECT_EQ(result.listens[0].recordingMBID->getAsString(), "46ae879f-2dbe-46d3-99ad-05c116f97a30");
+ EXPECT_EQ(result.listens[0].recordingMBID->toString(), "46ae879f-2dbe-46d3-99ad-05c116f97a30");
ASSERT_TRUE(result.listens[0].releaseMBID.has_value());
- EXPECT_EQ(result.listens[0].releaseMBID->getAsString(), "44915500-fbb9-4060-98ce-59a57a429edc");
+ EXPECT_EQ(result.listens[0].releaseMBID->toString(), "44915500-fbb9-4060-98ce-59a57a429edc");
EXPECT_EQ(result.listens[0].trackNumber, 5);
EXPECT_EQ(result.listens[1].trackName, "Melt");
EXPECT_EQ(result.listens[1].releaseName, "Petal");
EXPECT_EQ(result.listens[1].artistName, "Broke For Free");
ASSERT_TRUE(result.listens[1].recordingMBID.has_value());
- EXPECT_EQ(result.listens[1].recordingMBID->getAsString(), "d89d042c-8cc1-4526-9080-5bab728ee15f");
+ EXPECT_EQ(result.listens[1].recordingMBID->toString(), "d89d042c-8cc1-4526-9080-5bab728ee15f");
ASSERT_TRUE(result.listens[1].releaseMBID.has_value());
- EXPECT_EQ(result.listens[1].releaseMBID->getAsString(), "44915500-fbb9-4060-98ce-59a57a429edc");
+ EXPECT_EQ(result.listens[1].releaseMBID->toString(), "44915500-fbb9-4060-98ce-59a57a429edc");
EXPECT_EQ(result.listens[1].trackNumber, 4);
}
@@ -84,9 +84,9 @@ namespace lms::scrobbling::listenBrainz::tests
EXPECT_EQ(result.listens[0].releaseName, "Petal");
EXPECT_EQ(result.listens[0].artistName, "Broke For Free");
ASSERT_TRUE(result.listens[0].recordingMBID.has_value());
- EXPECT_EQ(result.listens[0].recordingMBID->getAsString(), "46ae879f-2dbe-46d3-99ad-05c116f97a30");
+ EXPECT_EQ(result.listens[0].recordingMBID->toString(), "46ae879f-2dbe-46d3-99ad-05c116f97a30");
ASSERT_TRUE(result.listens[0].releaseMBID.has_value());
- EXPECT_EQ(result.listens[0].releaseMBID->getAsString(), "44915500-fbb9-4060-98ce-59a57a429edc");
+ EXPECT_EQ(result.listens[0].releaseMBID->toString(), "44915500-fbb9-4060-98ce-59a57a429edc");
EXPECT_EQ(result.listens[0].trackNumber, 5);
}
diff --git a/src/libs/subsonic/impl/endpoints/Browsing.cpp b/src/libs/subsonic/impl/endpoints/Browsing.cpp
index 5092e535..98c55b5e 100644
--- a/src/libs/subsonic/impl/endpoints/Browsing.cpp
+++ b/src/libs/subsonic/impl/endpoints/Browsing.cpp
@@ -561,10 +561,10 @@ namespace lms::api::subsonic
switch (context.getResponseFormat())
{
case ResponseFormat::json:
- artistInfoNode.setAttribute("musicBrainzId", artistMBID->getAsString());
+ artistInfoNode.setAttribute("musicBrainzId", artistMBID->toString());
break;
case ResponseFormat::xml:
- artistInfoNode.createChild("musicBrainzId").setValue(artistMBID->getAsString());
+ artistInfoNode.createChild("musicBrainzId").setValue(artistMBID->toString());
break;
}
}
diff --git a/src/libs/subsonic/impl/endpoints/Transcoding.cpp b/src/libs/subsonic/impl/endpoints/Transcoding.cpp
index b9112e5b..2ef4bc08 100644
--- a/src/libs/subsonic/impl/endpoints/Transcoding.cpp
+++ b/src/libs/subsonic/impl/endpoints/Transcoding.cpp
@@ -108,7 +108,7 @@ namespace lms::api::subsonic
const core::UUID uuid{ getTranscodeDecisionTracker().add(audioFileId, transcodeRes.targetStreamInfo) };
transcodeNode.addChild("transcodeStream", createStreamDetails(transcodeRes.targetStreamInfo));
- transcodeNode.setAttribute("transcodeParams", uuid.getAsString());
+ transcodeNode.setAttribute("transcodeParams", uuid.toString());
},
[&](const detail::FailureResult& failureRes) {
transcodeNode.setAttribute("canDirectPlay", false);
diff --git a/src/libs/subsonic/impl/responses/Album.cpp b/src/libs/subsonic/impl/responses/Album.cpp
index 3baf3bd2..7d7fa1d6 100644
--- a/src/libs/subsonic/impl/responses/Album.cpp
+++ b/src/libs/subsonic/impl/responses/Album.cpp
@@ -165,7 +165,7 @@ namespace lms::api::subsonic
{
std::optional mbid{ release->getMBID() };
- albumNode.setAttribute("musicBrainzId", mbid ? mbid->getAsString() : "");
+ albumNode.setAttribute("musicBrainzId", mbid ? mbid->toString() : "");
}
auto addClusters{ [&](Response::Node::Key field, std::string_view clusterTypeName) {
diff --git a/src/libs/subsonic/impl/responses/AlbumInfo.cpp b/src/libs/subsonic/impl/responses/AlbumInfo.cpp
index e58b07c7..3831d324 100644
--- a/src/libs/subsonic/impl/responses/AlbumInfo.cpp
+++ b/src/libs/subsonic/impl/responses/AlbumInfo.cpp
@@ -34,10 +34,10 @@ namespace lms::api::subsonic
switch (context.getResponseFormat())
{
case ResponseFormat::json:
- albumInfo.setAttribute("musicBrainzId", releaseMBID->getAsString());
+ albumInfo.setAttribute("musicBrainzId", releaseMBID->toString());
break;
case ResponseFormat::xml:
- albumInfo.createChild("musicBrainzId").setValue(releaseMBID->getAsString());
+ albumInfo.createChild("musicBrainzId").setValue(releaseMBID->toString());
break;
}
}
diff --git a/src/libs/subsonic/impl/responses/Artist.cpp b/src/libs/subsonic/impl/responses/Artist.cpp
index 577d97c7..297e6ad0 100644
--- a/src/libs/subsonic/impl/responses/Artist.cpp
+++ b/src/libs/subsonic/impl/responses/Artist.cpp
@@ -102,7 +102,7 @@ namespace lms::api::subsonic
{
std::optional mbid{ artist->getMBID() };
- artistNode.setAttribute("musicBrainzId", mbid ? mbid->getAsString() : "");
+ artistNode.setAttribute("musicBrainzId", mbid ? mbid->toString() : "");
}
artistNode.setAttribute("sortName", artist->getSortName());
diff --git a/src/libs/subsonic/impl/responses/Song.cpp b/src/libs/subsonic/impl/responses/Song.cpp
index c20a0de0..fb8c7281 100644
--- a/src/libs/subsonic/impl/responses/Song.cpp
+++ b/src/libs/subsonic/impl/responses/Song.cpp
@@ -192,7 +192,7 @@ namespace lms::api::subsonic
{
std::optional mbid{ track->getRecordingMBID() };
- trackResponse.setAttribute("musicBrainzId", mbid ? mbid->getAsString() : "");
+ trackResponse.setAttribute("musicBrainzId", mbid ? mbid->toString() : "");
}
{
diff --git a/src/lms/ui/Utils.cpp b/src/lms/ui/Utils.cpp
index a5425d9e..4ac236a5 100644
--- a/src/lms/ui/Utils.cpp
+++ b/src/lms/ui/Utils.cpp
@@ -59,7 +59,7 @@ namespace lms::ui::utils
Wt::WLink createArtistLink(const db::Artist::pointer& artist)
{
if (const auto mbid{ artist->getMBID() })
- return Wt::WLink{ Wt::LinkType::InternalPath, "/artist/mbid/" + std::string{ mbid->getAsString() } };
+ return Wt::WLink{ Wt::LinkType::InternalPath, "/artist/mbid/" + mbid->toString() };
else
return Wt::WLink{ Wt::LinkType::InternalPath, "/artist/" + artist->getId().toString() };
}
@@ -229,7 +229,7 @@ namespace lms::ui::utils
Wt::WLink createReleaseLink(db::Release::pointer release)
{
if (const auto mbid{ release->getMBID() })
- return Wt::WLink{ Wt::LinkType::InternalPath, "/release/mbid/" + std::string{ mbid->getAsString() } };
+ return Wt::WLink{ Wt::LinkType::InternalPath, "/release/mbid/" + mbid->toString() };
return Wt::WLink{ Wt::LinkType::InternalPath, "/release/" + release->getId().toString() };
}
diff --git a/src/lms/ui/admin/ScannerReportResource.cpp b/src/lms/ui/admin/ScannerReportResource.cpp
index 8a1c369a..acc4bfbd 100644
--- a/src/lms/ui/admin/ScannerReportResource.cpp
+++ b/src/lms/ui/admin/ScannerReportResource.cpp
@@ -150,7 +150,7 @@ namespace lms::ui
response.out() << track->getAbsoluteFilePath().string();
if (auto mbid{ track->getTrackMBID() })
- response.out() << " (Track MBID " << mbid->getAsString() << ")";
+ response.out() << " (Track MBID " << mbid->toString() << ")";
response.out() << " - " << duplicateReasonToWString(duplicate.reason).toUTF8() << '\n';
}
diff --git a/src/lms/ui/admin/UserView.cpp b/src/lms/ui/admin/UserView.cpp
index 9af91ce6..74cbed9f 100644
--- a/src/lms/ui/admin/UserView.cpp
+++ b/src/lms/ui/admin/UserView.cpp
@@ -107,7 +107,7 @@ namespace lms::ui
user.modify()->setType(db::UserType::DEMO);
// For demo user, we create the subsonic API auth token now as we have no other mean to create it later
- core::Service::get()->createAuthToken("subsonic", user->getId(), core::UUID::generate().getAsString());
+ core::Service::get()->createAuthToken("subsonic", user->getId(), core::UUID::generate().toString());
}
if (_authPasswordService)
diff --git a/src/lms/ui/explore/ArtistView.cpp b/src/lms/ui/explore/ArtistView.cpp
index e1bea7e0..8883fbd7 100644
--- a/src/lms/ui/explore/ArtistView.cpp
+++ b/src/lms/ui/explore/ArtistView.cpp
@@ -393,7 +393,7 @@ namespace lms::ui
if (mbid)
{
setCondition("if-has-mbid", true);
- bindString("mbid-link", std::string{ "https://musicbrainz.org/artist/" } + std::string{ mbid->getAsString() });
+ bindString("mbid-link", "https://musicbrainz.org/artist/" + mbid->toString());
}
}
diff --git a/src/lms/ui/explore/ReleaseView.cpp b/src/lms/ui/explore/ReleaseView.cpp
index 9f1455d6..d11ed45c 100644
--- a/src/lms/ui/explore/ReleaseView.cpp
+++ b/src/lms/ui/explore/ReleaseView.cpp
@@ -554,7 +554,7 @@ namespace lms::ui
if (mbid)
{
setCondition("if-has-mbid", true);
- bindString("mbid-link", std::string{ "https://musicbrainz.org/release/" } + std::string{ mbid->getAsString() });
+ bindString("mbid-link", "https://musicbrainz.org/release/" + mbid->toString());
}
}
diff --git a/src/lms/ui/settings/SubsonicSettingsView.cpp b/src/lms/ui/settings/SubsonicSettingsView.cpp
index 97ad929c..27cc51e5 100644
--- a/src/lms/ui/settings/SubsonicSettingsView.cpp
+++ b/src/lms/ui/settings/SubsonicSettingsView.cpp
@@ -225,7 +225,7 @@ namespace lms::ui
}
auto doGenerate{ [subsonicTokenPtr, updateKeyButtonStates] {
- const std::string newToken{ core::UUID::generate().getAsString() };
+ const std::string newToken{ core::UUID::generate().toString() };
{
auto transaction{ LmsApp->getDbSession().createWriteTransaction() };
auto& authService{ *core::Service::get() };
diff --git a/src/tools/db-generator/LmsDbGenerator.cpp b/src/tools/db-generator/LmsDbGenerator.cpp
index f1c0a5bf..0d2a8054 100644
--- a/src/tools/db-generator/LmsDbGenerator.cpp
+++ b/src/tools/db-generator/LmsDbGenerator.cpp
@@ -78,14 +78,14 @@ namespace lms
db::Cluster::pointer generateCluster(db::Session& session, db::ClusterType::pointer clusterType)
{
- const std::string clusterName{ std::string{ clusterType->getName() } + "-" + std::string{ core::UUID::generate().getAsString() } };
+ const std::string clusterName{ std::string{ clusterType->getName() } + "-" + core::UUID::generate().toString() };
return session.create(clusterType, clusterName);
}
db::Artist::pointer generateArtist(db::Session& session)
{
const core::UUID artistMBID{ core::UUID::generate() };
- const std::string artistName{ "Artist-" + std::string{ core::UUID::generate().getAsString() } };
+ const std::string artistName{ "Artist-" + core::UUID::generate().toString() };
return session.create(artistName, artistMBID);
}
@@ -94,7 +94,7 @@ namespace lms
using namespace db;
const core::UUID releaseMBID{ core::UUID::generate() };
- const std::string releaseName{ "Release-" + std::string{ core::UUID::generate().getAsString() } };
+ const std::string releaseName{ "Release-" + core::UUID::generate().toString() };
Release::pointer release{ context.session.create(releaseName, releaseMBID) };
Medium::pointer medium{ context.session.create(release) };
medium.modify()->setTrackCount(params.trackCountPerRelease);
@@ -113,7 +113,7 @@ namespace lms
{
Track::pointer track{ context.session.create