diff --git a/src/libs/database/impl/objects/Artist.cpp b/src/libs/database/impl/objects/Artist.cpp index f74971d0..04547009 100644 --- a/src/libs/database/impl/objects/Artist.cpp +++ b/src/libs/database/impl/objects/Artist.cpp @@ -34,6 +34,7 @@ #include "SqlQuery.hpp" #include "Utils.hpp" +#include "objects/detail/Types.hpp" #include "traits/IdTypeTraits.hpp" #include "traits/StringViewTraits.hpp" @@ -56,6 +57,7 @@ namespace lms::db || params.track.isValid() || params.release.isValid() || params.filters.clusters.size() == 1 + || params.filters.codec.has_value() || params.filters.mediaLibrary.isValid() || params.filters.label.isValid() || params.filters.releaseType.isValid()) @@ -67,6 +69,7 @@ namespace lms::db || params.sortMethod == ArtistSortMethod::AddedDesc || params.writtenAfter.isValid() || params.release.isValid() + || params.filters.codec.has_value() || params.filters.mediaLibrary.isValid() || params.filters.label.isValid() || params.filters.releaseType.isValid()) @@ -79,6 +82,9 @@ namespace lms::db if (params.release.isValid()) query.where("t.release_id = ?").bind(params.release); + if (params.filters.codec.has_value()) + query.where("t.codec = ?").bind(detail::getDbCodecType(*params.filters.codec)); + if (params.filters.mediaLibrary.isValid()) query.where("t.media_library_id = ?").bind(params.filters.mediaLibrary); diff --git a/src/libs/database/impl/objects/Listen.cpp b/src/libs/database/impl/objects/Listen.cpp index 8fd3ac05..8ec09058 100644 --- a/src/libs/database/impl/objects/Listen.cpp +++ b/src/libs/database/impl/objects/Listen.cpp @@ -28,6 +28,7 @@ #include "SqlQuery.hpp" #include "Utils.hpp" +#include "objects/detail/Types.hpp" #include "traits/IdTypeTraits.hpp" DBO_INSTANTIATE_TEMPLATES(lms::db::Listen) @@ -49,11 +50,15 @@ namespace lms::db assert(!params.artist.isValid()); // poor check if (params.filters.mediaLibrary.isValid() + || params.filters.codec.has_value() || params.filters.label.isValid() || params.filters.releaseType.isValid()) { query.join("track t ON t.id = t_a_l.track_id"); + if (params.filters.codec.has_value()) + query.where("t.codec = ?").bind(detail::getDbCodecType(*params.filters.codec)); + if (params.filters.mediaLibrary.isValid()) query.where("t.media_library_id = ?").bind(params.filters.mediaLibrary); diff --git a/src/libs/database/impl/objects/Release.cpp b/src/libs/database/impl/objects/Release.cpp index 6f572a2c..d0442de6 100644 --- a/src/libs/database/impl/objects/Release.cpp +++ b/src/libs/database/impl/objects/Release.cpp @@ -75,6 +75,7 @@ namespace lms::db || params.artist.isValid() || params.filters.clusters.size() == 1 || params.filters.mediaLibrary.isValid() + || params.filters.codec.has_value() || params.directory.isValid() || params.parentDirectory.isValid()) { @@ -218,6 +219,9 @@ namespace lms::db query.where(oss.str()); } + if (params.filters.codec.has_value()) + query.where("t.codec = ?").bind(detail::getDbCodecType(params.filters.codec.value())); + if (params.releaseGroupMBID) query.where("group_mbid = ?").bind(params.releaseGroupMBID->getAsString()); diff --git a/src/libs/database/impl/objects/Track.cpp b/src/libs/database/impl/objects/Track.cpp index 5ad089b2..b089e19e 100644 --- a/src/libs/database/impl/objects/Track.cpp +++ b/src/libs/database/impl/objects/Track.cpp @@ -197,6 +197,9 @@ namespace lms::db query.where("t_e_i_l.track_embedded_image_id = ?").bind(params.embeddedImageId); } + if (params.filters.codec.has_value()) + query.where("t.codec = ?").bind(detail::getDbCodecType(*params.filters.codec)); + switch (params.sortMethod) { case TrackSortMethod::None: diff --git a/src/libs/database/impl/objects/TrackList.cpp b/src/libs/database/impl/objects/TrackList.cpp index 5ef0393c..55c4b06e 100644 --- a/src/libs/database/impl/objects/TrackList.cpp +++ b/src/libs/database/impl/objects/TrackList.cpp @@ -31,6 +31,7 @@ #include "SqlQuery.hpp" #include "Utils.hpp" +#include "objects/detail/Types.hpp" #include "traits/IdTypeTraits.hpp" #include "traits/StringViewTraits.hpp" @@ -49,6 +50,7 @@ namespace lms::db auto query{ session.getDboSession()->query("SELECT " + std::string{ itemToSelect } + " FROM tracklist t_l") }; if (!params.filters.clusters.empty() + || params.filters.codec.has_value() || params.filters.mediaLibrary.isValid() || params.filters.label.isValid() || params.filters.releaseType.isValid()) @@ -61,11 +63,15 @@ namespace lms::db query.where("t_l.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind("%" + utils::escapeForLikeKeyword(keyword) + "%"); if (params.filters.mediaLibrary.isValid() + || params.filters.codec.has_value() || params.filters.label.isValid() || params.filters.releaseType.isValid()) { query.join("track t ON t.id = t_l_e.track_id"); + if (params.filters.codec.has_value()) + query.where("t.codec = ?").bind(detail::getDbCodecType(*params.filters.codec)); + if (params.filters.mediaLibrary.isValid()) query.where("t.media_library_id = ?").bind(params.filters.mediaLibrary); diff --git a/src/libs/database/include/database/objects/Filters.hpp b/src/libs/database/include/database/objects/Filters.hpp index 1d95a09f..ead8f741 100644 --- a/src/libs/database/include/database/objects/Filters.hpp +++ b/src/libs/database/include/database/objects/Filters.hpp @@ -19,9 +19,12 @@ #pragma once +#include #include #include +#include "core/media/CodecType.hpp" + #include "database/objects/ClusterId.hpp" #include "database/objects/LabelId.hpp" #include "database/objects/MediaLibraryId.hpp" @@ -31,10 +34,11 @@ namespace lms::db { struct Filters { - MediaLibraryId mediaLibrary; // tracks that belongs to this library - std::vector clusters; // tracks that belong to all these clusters - LabelId label; // tracks which release has this label - ReleaseTypeId releaseType; // tracks which release has this type + MediaLibraryId mediaLibrary; // tracks that belongs to this library + std::vector clusters; // tracks that belong to *all* these clusters + LabelId label; // tracks which release has this label + ReleaseTypeId releaseType; // tracks which release has this type + std::optional codec; // tracks that match this codec Filters& setClusters(std::span _clusters) { @@ -56,5 +60,10 @@ namespace lms::db releaseType = _releaseType; return *this; } + Filters& setCodec(std::optional _codec) + { + codec = _codec; + return *this; + } }; } // namespace lms::db \ No newline at end of file diff --git a/src/libs/database/include/database/objects/Track.hpp b/src/libs/database/include/database/objects/Track.hpp index b1d2d38a..3cdfc664 100644 --- a/src/libs/database/include/database/objects/Track.hpp +++ b/src/libs/database/include/database/objects/Track.hpp @@ -350,7 +350,7 @@ namespace lms::db Wt::Dbo::field(a, _copyright, "copyright"); Wt::Dbo::field(a, _copyrightURL, "copyright_url"); Wt::Dbo::field(a, _artistDisplayName, "artist_display_name"); - Wt::Dbo::field(a, _comment, "comment"); // TODO: move in a dedicated table + Wt::Dbo::field(a, _comment, "comment"); // TODO: move in a dedicated table? Wt::Dbo::field(a, _advisory, "advisory"); Wt::Dbo::belongsTo(a, _medium, "medium", Wt::Dbo::OnDeleteCascade); diff --git a/src/libs/database/test/Artist.cpp b/src/libs/database/test/Artist.cpp index 0e443db8..5ae331ed 100644 --- a/src/libs/database/test/Artist.cpp +++ b/src/libs/database/test/Artist.cpp @@ -518,6 +518,34 @@ namespace lms::db::tests } } + TEST_F(DatabaseFixture, Artist_findByCodec) + { + ScopedArtist artist1{ session, "A" }; + ScopedArtist artist2{ session, "B" }; + ScopedTrack track1{ session }; + ScopedTrack track2{ session }; + + { + auto transaction{ session.createWriteTransaction() }; + TrackArtistLink::create(session, track1.get(), artist1.get(), TrackArtistLinkType::Artist); + TrackArtistLink::create(session, track2.get(), artist2.get(), TrackArtistLinkType::Artist); + + track1.get().modify()->setCodec(core::media::CodecType::MP3); + track2.get().modify()->setCodec(core::media::CodecType::FLAC); + } + + { + auto transaction{ session.createReadTransaction() }; + + Artist::FindParameters params; + params.setFilters(Filters{}.setCodec(core::media::CodecType::FLAC)); + + const auto artists{ Artist::find(session, params) }; + ASSERT_EQ(artists.results.size(), 1); + EXPECT_EQ(artists.results.front()->getId(), artist2.getId()); + } + } + TEST_F(DatabaseFixture, Artist_findByName) { ScopedArtist artist{ session, "AAA" }; diff --git a/src/libs/database/test/Release.cpp b/src/libs/database/test/Release.cpp index 4b2757a0..a7419ba9 100644 --- a/src/libs/database/test/Release.cpp +++ b/src/libs/database/test/Release.cpp @@ -1248,6 +1248,40 @@ namespace lms::db::tests } } + TEST_F(DatabaseFixture, Release_findBycodec) + { + ScopedRelease release1{ session, "MyRelease1" }; + ScopedTrack track1{ session }; + + ScopedRelease release2{ session, "MyRelease2" }; + ScopedTrack track2{ session }; + + { + auto transaction{ session.createReadTransaction() }; + ASSERT_EQ(release1->getCodecs().size(), 0); + } + + { + auto transaction{ session.createWriteTransaction() }; + track1.get().modify()->setCodec(core::media::CodecType::FLAC); + track1.get().modify()->setRelease(release1.get()); + + track2.get().modify()->setCodec(core::media::CodecType::MP3); + track2.get().modify()->setRelease(release2.get()); + } + + { + auto transaction{ session.createReadTransaction() }; + + Release::FindParameters params; + params.setFilters(Filters{}.setCodec(core::media::CodecType::MP3)); + + auto releases{ Release::findIds(session, params) }; + ASSERT_EQ(releases.results.size(), 1); + EXPECT_EQ(releases.results.front(), release2.getId()); + } + } + TEST_F(DatabaseFixture, Release_trackCount) { ScopedRelease release1{ session, "MyRelease1" }; diff --git a/src/libs/database/test/Track.cpp b/src/libs/database/test/Track.cpp index 9b83cf63..79c54bc9 100644 --- a/src/libs/database/test/Track.cpp +++ b/src/libs/database/test/Track.cpp @@ -238,27 +238,26 @@ namespace lms::db::tests } } - TEST_F(DatabaseFixture, Track_findAbsoluteFilePath) + TEST_F(DatabaseFixture, Track_findByCodec) { - ScopedTrack track{ session }; - const std::filesystem::path absoluteFilePath{ "/path/to/track.mp3" }; + ScopedTrack track1{ session }; + ScopedTrack track2{ session }; + { auto transaction{ session.createWriteTransaction() }; - track.get().modify()->setAbsoluteFilePath(absoluteFilePath); + track1.get().modify()->setCodec(core::media::CodecType::MP3); + track2.get().modify()->setCodec(core::media::CodecType::FLAC); } { auto transaction{ session.createReadTransaction() }; - TrackId lastRetrievedTrackId; - std::vector> visitedTracks; - Track::findAbsoluteFilePath(session, lastRetrievedTrackId, 10, [&](TrackId trackId, const std::filesystem::path& filePath) { - visitedTracks.emplace_back(trackId, filePath); - }); - ASSERT_EQ(visitedTracks.size(), 1); - EXPECT_EQ(visitedTracks[0].first, track.getId()); - EXPECT_EQ(visitedTracks[0].second, absoluteFilePath); - EXPECT_EQ(lastRetrievedTrackId, track.getId()); + Track::FindParameters params; + params.setFilters(Filters{}.setCodec(core::media::CodecType::FLAC)); + + const auto tracks{ Track::find(session, params) }; + ASSERT_EQ(tracks.results.size(), 1); + EXPECT_EQ(tracks.results[0]->getId(), track2.getId()); } }