Auto reformatted the base, ref #470

This commit is contained in:
emeric
2024-05-24 23:31:52 +02:00
parent 83b868673c
commit 39941d90a3
460 changed files with 8583 additions and 8514 deletions
+45 -26
View File
@@ -53,7 +53,8 @@ namespace lms::av
public: public:
AudioFileException(int avError) AudioFileException(int avError)
: Exception{ "AudioFileException: " + averror_to_string(avError) } : Exception{ "AudioFileException: " + averror_to_string(avError) }
{} {
}
}; };
void getMetaDataFromDictionnary(AVDictionary* dictionnary, AudioFile::MetadataMap& res) void getMetaDataFromDictionnary(AVDictionary* dictionnary, AudioFile::MetadataMap& res)
@@ -72,32 +73,52 @@ namespace lms::av
{ {
switch (codec) switch (codec)
{ {
case AV_CODEC_ID_MP3: return DecodingCodec::MP3; case AV_CODEC_ID_MP3:
case AV_CODEC_ID_AAC: return DecodingCodec::AAC; return DecodingCodec::MP3;
case AV_CODEC_ID_AC3: return DecodingCodec::AC3; case AV_CODEC_ID_AAC:
case AV_CODEC_ID_VORBIS: return DecodingCodec::VORBIS; return DecodingCodec::AAC;
case AV_CODEC_ID_WMAV1: return DecodingCodec::WMAV1; case AV_CODEC_ID_AC3:
case AV_CODEC_ID_WMAV2: return DecodingCodec::WMAV2; return DecodingCodec::AC3;
case AV_CODEC_ID_FLAC: return DecodingCodec::FLAC; case AV_CODEC_ID_VORBIS:
case AV_CODEC_ID_ALAC: return DecodingCodec::ALAC; return DecodingCodec::VORBIS;
case AV_CODEC_ID_WAVPACK: return DecodingCodec::WAVPACK; case AV_CODEC_ID_WMAV1:
case AV_CODEC_ID_MUSEPACK7: return DecodingCodec::MUSEPACK7; return DecodingCodec::WMAV1;
case AV_CODEC_ID_MUSEPACK8: return DecodingCodec::MUSEPACK8; case AV_CODEC_ID_WMAV2:
case AV_CODEC_ID_APE: return DecodingCodec::APE; return DecodingCodec::WMAV2;
case AV_CODEC_ID_EAC3: return DecodingCodec::EAC3; case AV_CODEC_ID_FLAC:
case AV_CODEC_ID_MP4ALS: return DecodingCodec::MP4ALS; return DecodingCodec::FLAC;
case AV_CODEC_ID_OPUS: return DecodingCodec::OPUS; case AV_CODEC_ID_ALAC:
case AV_CODEC_ID_SHORTEN: return DecodingCodec::SHORTEN; return DecodingCodec::ALAC;
case AV_CODEC_ID_DSD_LSBF: return DecodingCodec::DSD_LSBF; case AV_CODEC_ID_WAVPACK:
case AV_CODEC_ID_DSD_LSBF_PLANAR: return DecodingCodec::DSD_LSBF_PLANAR; return DecodingCodec::WAVPACK;
case AV_CODEC_ID_DSD_MSBF: return DecodingCodec::DSD_MSBF; case AV_CODEC_ID_MUSEPACK7:
case AV_CODEC_ID_DSD_MSBF_PLANAR: return DecodingCodec::DSD_MSBF_PLANAR; return DecodingCodec::MUSEPACK7;
case AV_CODEC_ID_MUSEPACK8:
return DecodingCodec::MUSEPACK8;
case AV_CODEC_ID_APE:
return DecodingCodec::APE;
case AV_CODEC_ID_EAC3:
return DecodingCodec::EAC3;
case AV_CODEC_ID_MP4ALS:
return DecodingCodec::MP4ALS;
case AV_CODEC_ID_OPUS:
return DecodingCodec::OPUS;
case AV_CODEC_ID_SHORTEN:
return DecodingCodec::SHORTEN;
case AV_CODEC_ID_DSD_LSBF:
return DecodingCodec::DSD_LSBF;
case AV_CODEC_ID_DSD_LSBF_PLANAR:
return DecodingCodec::DSD_LSBF_PLANAR;
case AV_CODEC_ID_DSD_MSBF:
return DecodingCodec::DSD_MSBF;
case AV_CODEC_ID_DSD_MSBF_PLANAR:
return DecodingCodec::DSD_MSBF_PLANAR;
default: default:
return DecodingCodec::UNKNOWN; return DecodingCodec::UNKNOWN;
} }
} }
} } // namespace
std::unique_ptr<IAudioFile> parseAudioFile(const std::filesystem::path& p) std::unique_ptr<IAudioFile> parseAudioFile(const std::filesystem::path& p)
{ {
@@ -218,8 +239,7 @@ namespace lms::av
void AudioFile::visitAttachedPictures(std::function<void(const Picture&)> func) const void AudioFile::visitAttachedPictures(std::function<void(const Picture&)> func) const
{ {
static const std::unordered_map<int, std::string> codecMimeMap = static const std::unordered_map<int, std::string> codecMimeMap{
{
{ AV_CODEC_ID_BMP, "image/x-bmp" }, { AV_CODEC_ID_BMP, "image/x-bmp" },
{ AV_CODEC_ID_GIF, "image/gif" }, { AV_CODEC_ID_GIF, "image/gif" },
{ AV_CODEC_ID_MJPEG, "image/jpeg" }, { AV_CODEC_ID_MJPEG, "image/jpeg" },
@@ -305,8 +325,7 @@ namespace lms::av
// List should be sync with the demuxers shipped in the lms's docker version // List should be sync with the demuxers shipped in the lms's docker version
// + the _audioFileExtensions in ScanSettings // + the _audioFileExtensions in ScanSettings
// std::filesystem::path does not seem to have std::hash specialization on freebsd // std::filesystem::path does not seem to have std::hash specialization on freebsd
static const std::unordered_map<std::string, std::string_view> entries static const std::unordered_map<std::string, std::string_view> entries{
{
{ ".mp3", "audio/mpeg" }, { ".mp3", "audio/mpeg" },
{ ".ogg", "audio/ogg" }, { ".ogg", "audio/ogg" },
{ ".oga", "audio/ogg" }, { ".oga", "audio/ogg" },
-3
View File
@@ -17,8 +17,6 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* This file contains some classes in order to get info from file using the libavconv */
#pragma once #pragma once
#include "av/IAudioFile.hpp" #include "av/IAudioFile.hpp"
@@ -54,4 +52,3 @@ namespace lms::av
}; };
} // namespace lms::av } // namespace lms::av
@@ -29,4 +29,4 @@ namespace lms::av
std::string_view mimeType{ getMimeType(path.extension()) }; std::string_view mimeType{ getMimeType(path.extension()) };
return createFileResourceHandler(path, mimeType.empty() ? "application/octet-stream" : mimeType); return createFileResourceHandler(path, mimeType.empty() ? "application/octet-stream" : mimeType);
} }
} } // namespace lms::av
+13 -9
View File
@@ -24,8 +24,8 @@
#include "core/IChildProcessManager.hpp" #include "core/IChildProcessManager.hpp"
#include "core/IConfig.hpp" #include "core/IConfig.hpp"
#include "core/Path.hpp"
#include "core/ILogger.hpp" #include "core/ILogger.hpp"
#include "core/Path.hpp"
#include "core/Service.hpp" #include "core/Service.hpp"
namespace lms::av::transcoding namespace lms::av::transcoding
@@ -40,11 +40,16 @@ namespace lms::av::transcoding
{ {
switch (format) switch (format)
{ {
case OutputFormat::MP3: return "audio/mpeg"; case OutputFormat::MP3:
case OutputFormat::OGG_OPUS: return "audio/opus"; return "audio/mpeg";
case OutputFormat::MATROSKA_OPUS: return "audio/x-matroska"; case OutputFormat::OGG_OPUS:
case OutputFormat::OGG_VORBIS: return "audio/ogg"; return "audio/opus";
case OutputFormat::WEBM_VORBIS: return "audio/webm"; case OutputFormat::MATROSKA_OPUS:
return "audio/x-matroska";
case OutputFormat::OGG_VORBIS:
return "audio/ogg";
case OutputFormat::WEBM_VORBIS:
return "audio/webm";
} }
throw Exception{ "Invalid encoding" }; throw Exception{ "Invalid encoding" };
@@ -195,8 +200,7 @@ namespace lms::av::transcoding
{ {
assert(_childProcess); assert(_childProcess);
return _childProcess->asyncRead(buffer, bufferSize, [readCallback{ std::move(readCallback) }](core::IChildProcess::ReadResult /*res*/, std::size_t nbBytesRead) return _childProcess->asyncRead(buffer, bufferSize, [readCallback{ std::move(readCallback) }](core::IChildProcess::ReadResult /*res*/, std::size_t nbBytesRead) {
{
readCallback(nbBytesRead); readCallback(nbBytesRead);
}); });
} }
@@ -215,4 +219,4 @@ namespace lms::av::transcoding
return _childProcess->finished(); return _childProcess->finished();
} }
} // namespace lms::av::Transcoding } // namespace lms::av::transcoding
+1 -1
View File
@@ -65,4 +65,4 @@ namespace lms::av::transcoding
std::unique_ptr<core::IChildProcess> _childProcess; std::unique_ptr<core::IChildProcess> _childProcess;
}; };
} } // namespace lms::av::transcoding
@@ -29,7 +29,7 @@ namespace lms::av::transcoding
const std::size_t estimatedContentLength{ outputParameters.bitrate / 8 * static_cast<std::size_t>(std::chrono::duration_cast<std::chrono::milliseconds>(inputParameters.duration).count()) / 1000 }; const std::size_t estimatedContentLength{ outputParameters.bitrate / 8 * static_cast<std::size_t>(std::chrono::duration_cast<std::chrono::milliseconds>(inputParameters.duration).count()) / 1000 };
return estimatedContentLength; return estimatedContentLength;
} }
} } // namespace
std::unique_ptr<IResourceHandler> createResourceHandler(const InputParameters& inputParameters, const OutputParameters& outputParameters, bool estimateContentLength) std::unique_ptr<IResourceHandler> createResourceHandler(const InputParameters& inputParameters, const OutputParameters& outputParameters, bool estimateContentLength)
{ {
@@ -68,8 +68,7 @@ namespace lms::av::transcoding
{ {
Wt::Http::ResponseContinuation* continuation{ response.createContinuation() }; Wt::Http::ResponseContinuation* continuation{ response.createContinuation() };
continuation->waitForMoreData(); continuation->waitForMoreData();
_transcoder.asyncRead(_buffer.data(), _buffer.size(), [this, continuation](std::size_t nbBytesRead) _transcoder.asyncRead(_buffer.data(), _buffer.size(), [this, continuation](std::size_t nbBytesRead) {
{
LMS_LOG(TRANSCODING, DEBUG, "Have " << nbBytesRead << " more bytes to send back"); LMS_LOG(TRANSCODING, DEBUG, "Have " << nbBytesRead << " more bytes to send back");
assert(_bytesReadyCount == 0); assert(_bytesReadyCount == 0);
@@ -99,5 +98,4 @@ namespace lms::av::transcoding
return {}; return {};
} }
} } // namespace lms::av::transcoding
@@ -25,6 +25,7 @@
#include "av/TranscodingParameters.hpp" #include "av/TranscodingParameters.hpp"
#include "core/IResourceHandler.hpp" #include "core/IResourceHandler.hpp"
#include "Transcoder.hpp" #include "Transcoder.hpp"
namespace lms::av::transcoding namespace lms::av::transcoding
@@ -45,5 +46,4 @@ namespace lms::av::transcoding
std::size_t _totalServedByteCount{}; std::size_t _totalServedByteCount{};
Transcoder _transcoder; Transcoder _transcoder;
}; };
} } // namespace lms::av::transcoding
+1 -4
View File
@@ -17,17 +17,15 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* This file contains some classes in order to get info from file using the libavconv */
#pragma once #pragma once
#include <chrono> #include <chrono>
#include <filesystem> #include <filesystem>
#include <functional> #include <functional>
#include <unordered_map>
#include <optional> #include <optional>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <unordered_map>
#include <vector> #include <vector>
#include "Types.hpp" #include "Types.hpp"
@@ -115,4 +113,3 @@ namespace lms::av
std::string_view getMimeType(const std::filesystem::path& fileExtension); std::string_view getMimeType(const std::filesystem::path& fileExtension);
} // namespace lms::av } // namespace lms::av
@@ -52,5 +52,4 @@ namespace lms::av::transcoding
std::chrono::milliseconds offset{ 0 }; std::chrono::milliseconds offset{ 0 };
bool stripMetadata{ true }; bool stripMetadata{ true };
}; };
} // namespace lms::av::Transcoding } // namespace lms::av::transcoding
@@ -29,4 +29,4 @@ namespace lms::av::transcoding
struct OutputParameters; struct OutputParameters;
std::unique_ptr<IResourceHandler> createResourceHandler(const InputParameters& inputParameters, const OutputParameters& outputParameters, bool estimateContentLength); std::unique_ptr<IResourceHandler> createResourceHandler(const InputParameters& inputParameters, const OutputParameters& outputParameters, bool estimateContentLength);
} } // namespace lms::av::transcoding
+1 -1
View File
@@ -28,4 +28,4 @@ namespace lms::av
public: public:
using LmsException::LmsException; using LmsException::LmsException;
}; };
} } // namespace lms::av
+3 -4
View File
@@ -17,9 +17,9 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <benchmark/benchmark.h>
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include <benchmark/benchmark.h> #include <benchmark/benchmark.h>
#include "core/ILogger.hpp" #include "core/ILogger.hpp"
@@ -59,8 +59,7 @@ namespace lms::core
static void BM_TraceLogger_Detailed_withArg(benchmark::State& state) static void BM_TraceLogger_Detailed_withArg(benchmark::State& state)
{ {
auto someExpensiveArgComputation{ []() -> std::string auto someExpensiveArgComputation{ []() -> std::string {
{
std::this_thread::sleep_for(std::chrono::microseconds{ 1 }); std::this_thread::sleep_for(std::chrono::microseconds{ 1 });
return "foo"; return "foo";
} }; } };
@@ -77,6 +76,6 @@ namespace lms::core
BENCHMARK(BM_TraceLogger_Detailed)->Threads(1)->Threads(std::thread::hardware_concurrency()); BENCHMARK(BM_TraceLogger_Detailed)->Threads(1)->Threads(std::thread::hardware_concurrency());
BENCHMARK(BM_TraceLogger_Detailed_withArg)->Threads(1)->Threads(std::thread::hardware_concurrency()); BENCHMARK(BM_TraceLogger_Detailed_withArg)->Threads(1)->Threads(std::thread::hardware_concurrency());
} } // namespace lms::core
BENCHMARK_MAIN(); BENCHMARK_MAIN();
+12 -12
View File
@@ -23,6 +23,7 @@
#include <cassert> #include <cassert>
#include <cstring> // strerror #include <cstring> // strerror
#include <fstream> #include <fstream>
#include <archive.h> #include <archive.h>
#include <archive_entry.h> #include <archive_entry.h>
@@ -40,11 +41,13 @@ namespace lms::zip
public: public:
FileException(const std::filesystem::path& p, std::string_view message) FileException(const std::filesystem::path& p, std::string_view message)
: Exception{ "File '" + p.string() + "': " + std::string{ message } } : Exception{ "File '" + p.string() + "': " + std::string{ message } }
{} {
}
FileException(const std::filesystem::path& p, std::string_view message, int err) FileException(const std::filesystem::path& p, std::string_view message, int err)
: Exception{ "File '" + p.string() + "': " + std::string{ message } + ": " + ::strerror(err) } : Exception{ "File '" + p.string() + "': " + std::string{ message } + ": " + ::strerror(err) }
{} {
}
}; };
class ArchiveException : public Exception class ArchiveException : public Exception
@@ -52,7 +55,8 @@ namespace lms::zip
public: public:
ArchiveException(struct ::archive* arch) ArchiveException(struct ::archive* arch)
: Exception{ getError(arch) } : Exception{ getError(arch) }
{} {
}
static std::string_view getError(struct ::archive* arch) static std::string_view getError(struct ::archive* arch)
{ {
@@ -88,19 +92,16 @@ namespace lms::zip
if (!_archive) if (!_archive)
throw Exception{ "Cannot create archive control struct" }; throw Exception{ "Cannot create archive control struct" };
auto archiveOpen{ [](struct ::archive*, void*) auto archiveOpen{ [](struct ::archive*, void*) {
{
return ARCHIVE_OK; return ARCHIVE_OK;
} }; } };
auto archiveWrite{ [](struct ::archive*, void* clientData, const void* buff, ::size_t n) -> la_ssize_t auto archiveWrite{ [](struct ::archive*, void* clientData, const void* buff, ::size_t n) -> la_ssize_t {
{
ArchiveZipper* zipper{ static_cast<ArchiveZipper*>(clientData) }; ArchiveZipper* zipper{ static_cast<ArchiveZipper*>(clientData) };
return zipper->onWriteCallback(static_cast<const std::byte*>(buff), n); return zipper->onWriteCallback(static_cast<const std::byte*>(buff), n);
} }; } };
auto archiveClose{ [](struct ::archive*, void*) auto archiveClose{ [](struct ::archive*, void*) {
{
return ARCHIVE_OK; return ARCHIVE_OK;
} }; } };
@@ -183,8 +184,7 @@ namespace lms::zip
using std::filesystem::perms; using std::filesystem::perms;
::mode_t mode{}; ::mode_t mode{};
auto testPerm{ [](perms p, perms permToTest) auto testPerm{ [](perms p, perms permToTest) {
{
return (p & permToTest) == permToTest; return (p & permToTest) == permToTest;
} }; } };
@@ -295,4 +295,4 @@ namespace lms::zip
return bufferSize; return bufferSize;
} }
} } // namespace lms::zip
+2 -1
View File
@@ -21,6 +21,7 @@
#include <cstddef> #include <cstddef>
#include <memory> #include <memory>
#include "core/IZipper.hpp" #include "core/IZipper.hpp"
extern "C" extern "C"
@@ -77,4 +78,4 @@ namespace lms::zip
std::uint64_t _bytesWrittenInCurrentOutputStream{}; std::uint64_t _bytesWrittenInCurrentOutputStream{};
}; };
} } // namespace lms::zip
+10 -9
View File
@@ -19,21 +19,21 @@
#include "ChildProcess.hpp" #include "ChildProcess.hpp"
#include <cstring>
#include <cerrno> #include <cerrno>
#include <cstring>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h>
#include <stdexcept> #include <stdexcept>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
#include <mutex> #include <mutex>
#include <boost/asio/read.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/asio/read.hpp>
#include "core/Exception.hpp" #include "core/Exception.hpp"
#include "core/ILogger.hpp" #include "core/ILogger.hpp"
@@ -47,13 +47,15 @@ namespace lms::core
public: public:
SystemException(int err, const std::string& errMsg) SystemException(int err, const std::string& errMsg)
: ChildProcessException{ errMsg + ": " + ::strerror(err) } : ChildProcessException{ errMsg + ": " + ::strerror(err) }
{} {
}
SystemException(boost::system::error_code ec, const std::string& errMsg) SystemException(boost::system::error_code ec, const std::string& errMsg)
: ChildProcessException{ errMsg + ": " + ec.message() } : ChildProcessException{ errMsg + ": " + ec.message() }
{} {
};
} }
};
} // namespace
ChildProcess::ChildProcess(boost::asio::io_context& ioContext, const std::filesystem::path& path, const Args& args) ChildProcess::ChildProcess(boost::asio::io_context& ioContext, const std::filesystem::path& path, const Args& args)
: _ioContext{ ioContext } : _ioContext{ ioContext }
@@ -170,8 +172,7 @@ namespace lms::core
LMS_LOG(CHILDPROCESS, DEBUG, "Async read, bufferSize = " << bufferSize); LMS_LOG(CHILDPROCESS, DEBUG, "Async read, bufferSize = " << bufferSize);
boost::asio::async_read(_childStdout, boost::asio::buffer(data, bufferSize), boost::asio::async_read(_childStdout, boost::asio::buffer(data, bufferSize),
[this, callback{ std::move(callback) }](const boost::system::error_code& error, std::size_t bytesTransferred) [this, callback{ std::move(callback) }](const boost::system::error_code& error, std::size_t bytesTransferred) {
{
LMS_LOG(CHILDPROCESS, DEBUG, "Async read cb - ec = '" << error.message() << "' (" << error.value() << "), bytesTransferred = " << bytesTransferred); LMS_LOG(CHILDPROCESS, DEBUG, "Async read cb - ec = '" << error.message() << "' (" << error.value() << "), bytesTransferred = " << bytesTransferred);
ReadResult readResult{ ReadResult::Success }; ReadResult readResult{ ReadResult::Success };
@@ -206,4 +207,4 @@ namespace lms::core
{ {
return _finished; return _finished;
} }
} } // namespace lms::core
+1 -1
View File
@@ -56,4 +56,4 @@ namespace lms::core
bool _finished{}; bool _finished{};
std::optional<int> _exitCode; std::optional<int> _exitCode;
}; };
} } // namespace lms::core
+1 -1
View File
@@ -39,4 +39,4 @@ namespace lms::core
{ {
return std::make_unique<ChildProcess>(_ioContext, path, args); return std::make_unique<ChildProcess>(_ioContext, path, args);
} }
} } // namespace lms::core
+1 -1
View File
@@ -44,4 +44,4 @@ namespace lms::core
boost::asio::io_context& _ioContext; boost::asio::io_context& _ioContext;
}; };
} } // namespace lms::core
+1 -1
View File
@@ -127,4 +127,4 @@ namespace lms::core
return def; return def;
} }
} }
} } // namespace lms::core
+1 -2
View File
@@ -45,7 +45,6 @@ namespace lms::core
bool getBool(std::string_view setting, bool def = false) override; bool getBool(std::string_view setting, bool def = false) override;
private: private:
libconfig::Config _config; libconfig::Config _config;
}; };
} } // namespace lms::core
+1 -1
View File
@@ -134,4 +134,4 @@ namespace lms
LMS_LOG(UTILS, DEBUG, "Job complete!"); LMS_LOG(UTILS, DEBUG, "Job complete!");
return nullptr; return nullptr;
} }
} } // namespace lms
+2 -1
View File
@@ -22,6 +22,7 @@
#include <filesystem> #include <filesystem>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include "core/IResourceHandler.hpp" #include "core/IResourceHandler.hpp"
namespace lms namespace lms
@@ -42,4 +43,4 @@ namespace lms
::uint64_t _beyondLastByte{}; ::uint64_t _beyondLastByte{};
::uint64_t _offset{}; ::uint64_t _offset{};
}; };
} } // namespace lms
+2 -3
View File
@@ -41,8 +41,7 @@ namespace lms::core
threadName += std::to_string(i); threadName += std::to_string(i);
} }
_threads.emplace_back([this, threadName] _threads.emplace_back([this, threadName] {
{
if (!threadName.empty()) if (!threadName.empty())
{ {
if (auto* traceLogger{ Service<tracing::ITraceLogger>::get() }) if (auto* traceLogger{ Service<tracing::ITraceLogger>::get() })
@@ -82,4 +81,4 @@ namespace lms::core
for (std::thread& t : _threads) for (std::thread& t : _threads)
t.join(); t.join();
} }
} } // namespace lms::core
+51 -26
View File
@@ -25,25 +25,44 @@ namespace lms::core::logging
{ {
switch (mod) switch (mod)
{ {
case Module::API_SUBSONIC: return "API_SUBSONIC"; case Module::API_SUBSONIC:
case Module::AUTH: return "AUTH"; return "API_SUBSONIC";
case Module::AV: return "AV"; case Module::AUTH:
case Module::CHILDPROCESS: return "CHILDPROC"; return "AUTH";
case Module::COVER: return "COVER"; case Module::AV:
case Module::DB: return "DB"; return "AV";
case Module::DBUPDATER: return "DB UPDATER"; case Module::CHILDPROCESS:
case Module::FEATURE: return "FEATURE"; return "CHILDPROC";
case Module::FEEDBACK: return "FEEDBACK"; case Module::COVER:
case Module::HTTP: return "HTTP"; return "COVER";
case Module::MAIN: return "MAIN"; case Module::DB:
case Module::METADATA: return "METADATA"; return "DB";
case Module::REMOTE: return "REMOTE"; case Module::DBUPDATER:
case Module::SCROBBLING: return "SCROBBLING"; return "DB UPDATER";
case Module::SERVICE: return "SERVICE"; case Module::FEATURE:
case Module::RECOMMENDATION: return "RECOMMENDATION"; return "FEATURE";
case Module::TRANSCODING: return "TRANSCODING"; case Module::FEEDBACK:
case Module::UI: return "UI"; return "FEEDBACK";
case Module::UTILS: return "UTILS"; case Module::HTTP:
return "HTTP";
case Module::MAIN:
return "MAIN";
case Module::METADATA:
return "METADATA";
case Module::REMOTE:
return "REMOTE";
case Module::SCROBBLING:
return "SCROBBLING";
case Module::SERVICE:
return "SERVICE";
case Module::RECOMMENDATION:
return "RECOMMENDATION";
case Module::TRANSCODING:
return "TRANSCODING";
case Module::UI:
return "UI";
case Module::UTILS:
return "UTILS";
} }
return ""; return "";
} }
@@ -52,11 +71,16 @@ namespace lms::core::logging
{ {
switch (sev) switch (sev)
{ {
case Severity::FATAL: return "fatal"; case Severity::FATAL:
case Severity::ERROR: return "error"; return "fatal";
case Severity::WARNING: return "warning"; case Severity::ERROR:
case Severity::INFO: return "info"; return "error";
case Severity::DEBUG: return "debug"; case Severity::WARNING:
return "warning";
case Severity::INFO:
return "info";
case Severity::DEBUG:
return "debug";
} }
return ""; return "";
} }
@@ -66,7 +90,8 @@ namespace lms::core::logging
, _module{ module } , _module{ module }
, _severity{ severity } , _severity{ severity }
{} {
}
Log::~Log() Log::~Log()
{ {
@@ -78,4 +103,4 @@ namespace lms::core::logging
{ {
return _oss.str(); return _oss.str();
} }
} } // namespace lms::core::logging
+1 -1
View File
@@ -41,6 +41,6 @@ namespace std
return std::hash<std::string>{}(ipAddr.to_string()); return std::hash<std::string>{}(ipAddr.to_string());
} }
} } // namespace std
#endif // BOOST_ASIO_HAS_STD_HASH #endif // BOOST_ASIO_HAS_STD_HASH
+7 -6
View File
@@ -19,12 +19,11 @@
#include "core/Path.hpp" #include "core/Path.hpp"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <array> #include <array>
#include <fstream> #include <fstream>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <boost/tokenizer.hpp> #include <boost/tokenizer.hpp>
@@ -69,7 +68,9 @@ namespace lms::core::pathUtils
Wt::WDateTime getLastWriteTime(const std::filesystem::path& file) Wt::WDateTime getLastWriteTime(const std::filesystem::path& file)
{ {
struct stat sb {}; struct stat sb
{
};
if (stat(file.string().c_str(), &sb) == -1) if (stat(file.string().c_str(), &sb) == -1)
throw LmsException("Failed to get stats on file '" + file.string() + "'"); throw LmsException("Failed to get stats on file '" + file.string() + "'");
@@ -183,4 +184,4 @@ namespace lms::core::pathUtils
return longestCommonPath; return longestCommonPath;
} }
} } // namespace lms::core::pathUtils
+1 -1
View File
@@ -35,4 +35,4 @@ namespace lms::core::random
return RandGenerator{ seed }; return RandGenerator{ seed };
} }
} } // namespace lms::core::random
+1 -1
View File
@@ -131,4 +131,4 @@ namespace lms::core
return _sharedCounts[thisThreadId] > 0; return _sharedCounts[thisThreadId] > 0;
} }
#endif #endif
} } // namespace lms::core
+1 -1
View File
@@ -35,4 +35,4 @@ namespace lms::core::logging
assert(isSeverityActive(log.getSeverity())); assert(isSeverityActive(log.getSeverity()));
_os << std::this_thread::get_id() << " [" << getSeverityName(log.getSeverity()) << "] [" << getModuleName(log.getModule()) << "] " << log.getMessage() << std::endl; _os << std::this_thread::get_id() << " [" << getSeverityName(log.getSeverity()) << "] [" << getModuleName(log.getModule()) << "] " << log.getMessage() << std::endl;
} }
} } // namespace lms::core::logging
+7 -8
View File
@@ -23,15 +23,14 @@
#include <iomanip> #include <iomanip>
#include <utility> #include <utility>
#include <Wt/WDateTime.h>
#include <Wt/WDate.h> #include <Wt/WDate.h>
#include <Wt/WDateTime.h>
namespace lms::core::stringUtils namespace lms::core::stringUtils
{ {
namespace details namespace details
{ {
constexpr std::pair<char, std::string_view> jsEscapeChars[] constexpr std::pair<char, std::string_view> jsEscapeChars[]{
{
{ '\\', "\\\\" }, { '\\', "\\\\" },
{ '\n', "\\n" }, { '\n', "\\n" },
{ '\r', "\\r" }, { '\r', "\\r" },
@@ -40,8 +39,7 @@ namespace lms::core::stringUtils
{ '\'', "\\\'" }, { '\'', "\\\'" },
}; };
constexpr std::pair<char, std::string_view> jsonEscapeChars[] constexpr std::pair<char, std::string_view> jsonEscapeChars[]{
{
{ '\\', "\\\\" }, { '\\', "\\\\" },
{ '\n', "\\n" }, { '\n', "\\n" },
{ '\r', "\\r" }, { '\r', "\\r" },
@@ -99,7 +97,7 @@ namespace lms::core::stringUtils
return res; return res;
} }
} } // namespace details
template<> template<>
std::optional<std::string> readAs(std::string_view str) std::optional<std::string> readAs(std::string_view str)
@@ -198,7 +196,8 @@ namespace lms::core::stringUtils
for (char c : str) for (char c : str)
{ {
if (escaped) { if (escaped)
{
current.push_back(c); current.push_back(c);
escaped = false; escaped = false;
} }
@@ -436,4 +435,4 @@ namespace lms::core::stringUtils
// assume UTC // assume UTC
return date.toString("yyyy-MM-dd").toUTF8(); return date.toString("yyyy-MM-dd").toUTF8();
} }
} } // namespace lms::core::stringUtils
+7 -4
View File
@@ -22,6 +22,7 @@
#include <iomanip> #include <iomanip>
#include <memory> #include <memory>
#include <string> #include <string>
#include "core/Exception.hpp" #include "core/Exception.hpp"
#include "core/ILogger.hpp" #include "core/ILogger.hpp"
@@ -32,7 +33,8 @@ namespace lms::core::tracing
class CurrentThreadUnregisterer class CurrentThreadUnregisterer
{ {
public: public:
CurrentThreadUnregisterer(TraceLogger* logger) : _logger{ logger } {} CurrentThreadUnregisterer(TraceLogger* logger)
: _logger{ logger } {}
~CurrentThreadUnregisterer() ~CurrentThreadUnregisterer()
{ {
if (_logger) if (_logger)
@@ -45,7 +47,7 @@ namespace lms::core::tracing
TraceLogger* _logger; TraceLogger* _logger;
}; };
} } // namespace
thread_local TraceLogger::Buffer* TraceLogger::_currentBuffer{}; thread_local TraceLogger::Buffer* TraceLogger::_currentBuffer{};
@@ -182,7 +184,8 @@ namespace lms::core::tracing
if (first) if (first)
first = false; first = false;
else else
os << ", " << std::endl;; os << ", " << std::endl;
;
os << "\t\t{ "; os << "\t\t{ ";
os << "\"name\" : \"" << event.name << "\", "; os << "\"name\" : \"" << event.name << "\", ";
@@ -297,4 +300,4 @@ namespace lms::core::tracing
return static_cast<std::uint32_t>(id); return static_cast<std::uint32_t>(id);
} }
} } // namespace lms::core::tracing
+1 -1
View File
@@ -103,4 +103,4 @@ namespace lms::core::tracing
static thread_local Buffer* _currentBuffer; static thread_local Buffer* _currentBuffer;
}; };
} } // namespace lms::core::tracing
+4 -5
View File
@@ -37,7 +37,7 @@ namespace lms::core
{ {
return UUID::fromString(str); return UUID::fromString(str);
} }
} } // namespace stringUtils
namespace namespace
{ {
bool stringIsUUID(std::string_view str) bool stringIsUUID(std::string_view str)
@@ -46,7 +46,7 @@ namespace lms::core
return std::regex_match(std::cbegin(str), std::cend(str), re); return std::regex_match(std::cbegin(str), std::cend(str), re);
} }
} } // namespace
UUID::UUID(std::string_view str) UUID::UUID(std::string_view str)
: _value{ stringUtils::stringToLower(str) } : _value{ stringUtils::stringToLower(str) }
@@ -68,8 +68,7 @@ namespace lms::core
std::ostringstream oss; std::ostringstream oss;
auto concatRandomBytes{ [](std::ostream& os, std::size_t byteCount) auto concatRandomBytes{ [](std::ostream& os, std::size_t byteCount) {
{
for (std::size_t i{}; i < byteCount; ++i) for (std::size_t i{}; i < byteCount; ++i)
os << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(random::getRandom<std::uint8_t>(0, 255)); os << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(random::getRandom<std::uint8_t>(0, 255));
} }; } };
@@ -88,4 +87,4 @@ namespace lms::core
assert(uuid); assert(uuid);
return uuid.value(); return uuid.value();
} }
} } // namespace lms::core
+15 -9
View File
@@ -19,10 +19,11 @@
#include "core/WtLogger.hpp" #include "core/WtLogger.hpp"
#include <thread>
#include <sstream> #include <sstream>
#include <Wt/WServer.h> #include <thread>
#include <Wt/WLogger.h> #include <Wt/WLogger.h>
#include <Wt/WServer.h>
#include "core/Exception.hpp" #include "core/Exception.hpp"
@@ -36,7 +37,7 @@ namespace lms::core::logging
oss << id; oss << id;
return oss.str(); return oss.str();
} }
} } // namespace
WtLogger::WtLogger(Severity minSeverity) WtLogger::WtLogger(Severity minSeverity)
: _minSeverity{ minSeverity } : _minSeverity{ minSeverity }
@@ -47,11 +48,16 @@ namespace lms::core::logging
{ {
switch (minSeverity) switch (minSeverity)
{ {
case Severity::DEBUG: return "*"; case Severity::DEBUG:
case Severity::INFO: return "* -debug"; return "*";
case Severity::WARNING: return "* -debug -info"; case Severity::INFO:
case Severity::ERROR: return "* -debug -info -warning"; return "* -debug";
case Severity::FATAL: return "* -debug -info -warning -error"; case Severity::WARNING:
return "* -debug -info";
case Severity::ERROR:
return "* -debug -info -warning";
case Severity::FATAL:
return "* -debug -info -warning -error";
} }
throw LmsException{ "Unhandled severity" }; throw LmsException{ "Unhandled severity" };
@@ -66,4 +72,4 @@ namespace lms::core::logging
{ {
Wt::log(getSeverityName(log.getSeverity())) << Wt::WLogger::sep << to_string(std::this_thread::get_id()) << Wt::WLogger::sep << "[" << getModuleName(log.getModule()) << "]" << Wt::WLogger::sep << log.getMessage(); Wt::log(getSeverityName(log.getSeverity())) << Wt::WLogger::sep << to_string(std::this_thread::get_id()) << Wt::WLogger::sep << "[" << getModuleName(log.getModule()) << "]" << Wt::WLogger::sep << log.getMessage();
} }
} } // namespace lms::core::logging
+1 -1
View File
@@ -36,4 +36,4 @@ namespace lms::core::http
{ {
_sendQueue.sendRequest(std::make_unique<ClientRequest>(std::move(POSTParams))); _sendQueue.sendRequest(std::make_unique<ClientRequest>(std::move(POSTParams)));
} }
} } // namespace lms::core::http
+6 -4
View File
@@ -19,11 +19,12 @@
#pragma once #pragma once
#include <unordered_map>
#include <string>
#include <shared_mutex> #include <shared_mutex>
#include <string>
#include <unordered_map>
#include "core/http/IClient.hpp" #include "core/http/IClient.hpp"
#include "SendQueue.hpp" #include "SendQueue.hpp"
namespace lms::core::http namespace lms::core::http
@@ -33,7 +34,8 @@ namespace lms::core::http
public: public:
Client(boost::asio::io_context& ioContext, std::string_view baseUrl) Client(boost::asio::io_context& ioContext, std::string_view baseUrl)
: _sendQueue{ ioContext, baseUrl } : _sendQueue{ ioContext, baseUrl }
{} {
}
private: private:
void sendGETRequest(ClientGETRequestParameters&& request) override; void sendGETRequest(ClientGETRequestParameters&& request) override;
@@ -41,4 +43,4 @@ namespace lms::core::http
SendQueue _sendQueue; SendQueue _sendQueue;
}; };
} } // namespace lms::core::http
+9 -6
View File
@@ -21,6 +21,7 @@
#include <memory> #include <memory>
#include <variant> #include <variant>
#include "core/http/ClientRequestParameters.hpp" #include "core/http/ClientRequestParameters.hpp"
namespace lms::core::http namespace lms::core::http
@@ -28,8 +29,10 @@ namespace lms::core::http
class ClientRequest class ClientRequest
{ {
public: public:
ClientRequest(ClientGETRequestParameters&& GETParams) : _parameters{ std::move(GETParams) } {} ClientRequest(ClientGETRequestParameters&& GETParams)
ClientRequest(ClientPOSTRequestParameters&& POSTParams) : _parameters{ std::move(POSTParams) } {} : _parameters{ std::move(GETParams) } {}
ClientRequest(ClientPOSTRequestParameters&& POSTParams)
: _parameters{ std::move(POSTParams) } {}
std::size_t retryCount{}; std::size_t retryCount{};
@@ -37,10 +40,10 @@ namespace lms::core::http
{ {
const ClientRequestParameters* res; const ClientRequestParameters* res;
std::visit([&](const auto& parameters) std::visit([&](const auto& parameters) {
{
res = &static_cast<const ClientRequestParameters&>(parameters); res = &static_cast<const ClientRequestParameters&>(parameters);
}, _parameters); },
_parameters);
return *res; return *res;
} }
@@ -71,4 +74,4 @@ namespace lms::core::http
private: private:
std::variant<ClientGETRequestParameters, ClientPOSTRequestParameters> _parameters; std::variant<ClientGETRequestParameters, ClientPOSTRequestParameters> _parameters;
}; };
} } // namespace lms::core::http
+8 -12
View File
@@ -19,8 +19,8 @@
#include "SendQueue.hpp" #include "SendQueue.hpp"
#include <boost/asio/dispatch.hpp>
#include <boost/asio/bind_executor.hpp> #include <boost/asio/bind_executor.hpp>
#include <boost/asio/dispatch.hpp>
#include "core/Exception.hpp" #include "core/Exception.hpp"
#include "core/ILogger.hpp" #include "core/ILogger.hpp"
@@ -41,7 +41,7 @@ namespace lms::core::stringUtils
return res; return res;
} }
} } // namespace lms::core::stringUtils
namespace lms::core::http namespace lms::core::http
{ {
@@ -57,16 +57,14 @@ namespace lms::core::http
return res; return res;
} }
} } // namespace
SendQueue::SendQueue(boost::asio::io_context& ioContext, std::string_view baseUrl) SendQueue::SendQueue(boost::asio::io_context& ioContext, std::string_view baseUrl)
: _ioContext{ ioContext } : _ioContext{ ioContext }
, _baseUrl{ baseUrl } , _baseUrl{ baseUrl }
{ {
_client.done().connect([this](Wt::AsioWrapper::error_code ec, const Wt::Http::Message& msg) _client.done().connect([this](Wt::AsioWrapper::error_code ec, const Wt::Http::Message& msg) {
{ _strand.dispatch([this, ec, msg = std::move(msg)] {
_strand.dispatch([this, ec, msg = std::move(msg)]
{
onClientDone(ec, msg); onClientDone(ec, msg);
}); });
}); });
@@ -79,8 +77,7 @@ namespace lms::core::http
void SendQueue::sendRequest(std::unique_ptr<ClientRequest> request) void SendQueue::sendRequest(std::unique_ptr<ClientRequest> request)
{ {
boost::asio::dispatch(_strand, [this, request = std::move(request)]() mutable boost::asio::dispatch(_strand, [this, request = std::move(request)]() mutable {
{
_sendQueue[request->getParameters().priority].emplace_back(std::move(request)); _sendQueue[request->getParameters().priority].emplace_back(std::move(request));
if (_state == State::Idle) if (_state == State::Idle)
@@ -220,8 +217,7 @@ namespace lms::core::http
LOG(DEBUG, "Throttling for " << duration.count() << " seconds"); LOG(DEBUG, "Throttling for " << duration.count() << " seconds");
_throttleTimer.expires_after(duration); _throttleTimer.expires_after(duration);
_throttleTimer.async_wait([this](const boost::system::error_code& ec) _throttleTimer.async_wait([this](const boost::system::error_code& ec) {
{
if (ec == boost::asio::error::operation_aborted) if (ec == boost::asio::error::operation_aborted)
{ {
LOG(DEBUG, "Throttle aborted"); LOG(DEBUG, "Throttle aborted");
@@ -237,4 +233,4 @@ namespace lms::core::http
}); });
_state = State::Throttled; _state = State::Throttled;
} }
} } // namespace lms::core::http
+3 -3
View File
@@ -20,14 +20,14 @@
#pragma once #pragma once
#include <deque> #include <deque>
#include <vector>
#include <string_view> #include <string_view>
#include <vector>
#include <Wt/Http/Client.h>
#include <boost/asio/io_context.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/io_context_strand.hpp> #include <boost/asio/io_context_strand.hpp>
#include <boost/asio/steady_timer.hpp> #include <boost/asio/steady_timer.hpp>
#include <Wt/Http/Client.h>
#include "ClientRequest.hpp" #include "ClientRequest.hpp"
namespace lms::core::http namespace lms::core::http
@@ -75,4 +75,4 @@ namespace lms::core::http
std::unique_ptr<ClientRequest> _currentRequest; std::unique_ptr<ClientRequest> _currentRequest;
}; };
} } // namespace lms::core::http
@@ -40,4 +40,4 @@ namespace lms::core
using Crc32Type = boost::crc_32_type; using Crc32Type = boost::crc_32_type;
Crc32Type _result; Crc32Type _result;
}; };
} } // namespace lms::core
+5 -2
View File
@@ -158,7 +158,10 @@ namespace lms::core
private: private:
static_assert(std::numeric_limits<IndexType>::max() >= sizeof(underlying_type) * 8); static_assert(std::numeric_limits<IndexType>::max() >= sizeof(underlying_type) * 8);
enum : IndexType { npos = sizeof(underlying_type) * 8 }; enum : IndexType
{
npos = sizeof(underlying_type) * 8
};
constexpr IndexType getFirstBitSetIndex(IndexType start = {}) const constexpr IndexType getFirstBitSetIndex(IndexType start = {}) const
{ {
@@ -190,4 +193,4 @@ namespace lms::core
underlying_type _bitfield{}; underlying_type _bitfield{};
}; };
} } // namespace lms::core
+3 -2
View File
@@ -29,6 +29,7 @@ namespace lms::core
class LmsException : public std::runtime_error class LmsException : public std::runtime_error
{ {
public: public:
LmsException(std::string_view error = "") : std::runtime_error{ std::string{ error } } {} LmsException(std::string_view error = "")
: std::runtime_error{ std::string{ error } } {}
}; };
} } // namespace lms::core
+1 -1
View File
@@ -53,4 +53,4 @@ namespace lms::core
virtual std::size_t readSome(std::byte* data, std::size_t bufferSize) = 0; virtual std::size_t readSome(std::byte* data, std::size_t bufferSize) = 0;
virtual bool finished() const = 0; virtual bool finished() const = 0;
}; };
} } // namespace lms::core
@@ -20,6 +20,7 @@
#include <filesystem> #include <filesystem>
#include <memory> #include <memory>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_service.hpp>
#include "IChildProcess.hpp" #include "IChildProcess.hpp"
@@ -35,4 +36,4 @@ namespace lms::core
}; };
std::unique_ptr<IChildProcessManager> createChildProcessManager(boost::asio::io_service& ioService); std::unique_ptr<IChildProcessManager> createChildProcessManager(boost::asio::io_service& ioService);
} } // namespace lms::core
+1 -1
View File
@@ -40,4 +40,4 @@ namespace lms::core
}; };
std::unique_ptr<IConfig> createConfig(const std::filesystem::path& p); std::unique_ptr<IConfig> createConfig(const std::filesystem::path& p);
} } // namespace lms::core
+3 -3
View File
@@ -19,11 +19,11 @@
#pragma once #pragma once
#include <string>
#include <sstream> #include <sstream>
#include <string>
#include "core/Service.hpp"
#include "core/String.hpp" #include "core/String.hpp"
#include "Service.hpp"
namespace lms::core::logging namespace lms::core::logging
{ {
@@ -93,7 +93,7 @@ namespace lms::core::logging
virtual bool isSeverityActive(Severity severity) const = 0; virtual bool isSeverityActive(Severity severity) const = 0;
virtual void processLog(const Log& log) = 0; virtual void processLog(const Log& log) = 0;
}; };
} } // namespace lms::core::logging
#define LMS_LOG(module, severity, message) \ #define LMS_LOG(module, severity, message) \
do \ do \
@@ -21,6 +21,7 @@
#include <optional> #include <optional>
#include <thread> #include <thread>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_service.hpp>
namespace lms::core namespace lms::core
@@ -42,4 +43,4 @@ namespace lms::core
std::optional<boost::asio::io_service::work> _work; std::optional<boost::asio::io_service::work> _work;
std::vector<std::thread> _threads; std::vector<std::thread> _threads;
}; };
} } // namespace lms::core
@@ -34,4 +34,4 @@ namespace lms
[[nodiscard]] virtual Wt::Http::ResponseContinuation* processRequest(const Wt::Http::Request& request, Wt::Http::Response& response) = 0; [[nodiscard]] virtual Wt::Http::ResponseContinuation* processRequest(const Wt::Http::Request& request, Wt::Http::Response& response) = 0;
virtual void abort() = 0; virtual void abort() = 0;
}; };
} } // namespace lms
+1 -1
View File
@@ -124,4 +124,4 @@ namespace lms::core::tracing
ITraceLogger* _traceLogger; ITraceLogger* _traceLogger;
ITraceLogger::CompleteEvent _event; ITraceLogger::CompleteEvent _event;
}; };
} } // namespace lms::core::tracing
+1 -1
View File
@@ -51,4 +51,4 @@ namespace lms::zip
}; };
std::unique_ptr<IZipper> createArchiveZipper(const EntryContainer& entries); std::unique_ptr<IZipper> createArchiveZipper(const EntryContainer& entries);
} } // namespace lms::zip
+24 -12
View File
@@ -31,7 +31,11 @@ namespace lms::core
public: public:
constexpr LiteralString() noexcept = default; constexpr LiteralString() noexcept = default;
template<std::size_t N> template<std::size_t N>
constexpr LiteralString(const char(&str)[N]) noexcept : _str{ str, N - 1 } { static_assert(N > 0); } constexpr LiteralString(const char (&str)[N]) noexcept
: _str{ str, N - 1 }
{
static_assert(N > 0);
}
constexpr bool empty() const noexcept { return _str.empty(); } constexpr bool empty() const noexcept { return _str.empty(); }
constexpr const char* c_str() const noexcept { return _str.data(); } constexpr const char* c_str() const noexcept { return _str.data(); }
@@ -48,7 +52,7 @@ namespace lms::core
os << str.str(); os << str.str();
return os; return os;
} }
} } // namespace lms::core
namespace std namespace std
{ {
@@ -60,7 +64,7 @@ namespace std
return hash<std::string_view>{}(str.str()); return hash<std::string_view>{}(str.str());
} }
}; };
} } // namespace std
namespace lms::core namespace lms::core
{ {
@@ -69,15 +73,18 @@ namespace lms::core
using hash_type = std::hash<std::string_view>; using hash_type = std::hash<std::string_view>;
using is_transparent = void; using is_transparent = void;
[[nodiscard]] size_t operator()(const LiteralString& str) const { [[nodiscard]] size_t operator()(const LiteralString& str) const
{
return hash_type{}(str.str()); return hash_type{}(str.str());
} }
[[nodiscard]] size_t operator()(std::string_view str) const { [[nodiscard]] size_t operator()(std::string_view str) const
{
return hash_type{}(str); return hash_type{}(str);
} }
[[nodiscard]] size_t operator()(const std::string& str) const { [[nodiscard]] size_t operator()(const std::string& str) const
{
return hash_type{}(str); return hash_type{}(str);
} }
}; };
@@ -86,24 +93,29 @@ namespace lms::core
{ {
using is_transparent = void; using is_transparent = void;
[[nodiscard]] bool operator()(const LiteralString& lhs, const LiteralString& rhs) const { [[nodiscard]] bool operator()(const LiteralString& lhs, const LiteralString& rhs) const
{
return lhs == rhs; return lhs == rhs;
} }
[[nodiscard]] bool operator()(const LiteralString& lhs, const std::string& rhs) const { [[nodiscard]] bool operator()(const LiteralString& lhs, const std::string& rhs) const
{
return lhs.str() == rhs; return lhs.str() == rhs;
} }
[[nodiscard]] bool operator()(const LiteralString& lhs, std::string_view rhs) const { [[nodiscard]] bool operator()(const LiteralString& lhs, std::string_view rhs) const
{
return lhs.str() == rhs; return lhs.str() == rhs;
} }
[[nodiscard]] bool operator()(const std::string_view& lhs, LiteralString rhs) const { [[nodiscard]] bool operator()(const std::string_view& lhs, LiteralString rhs) const
{
return lhs == rhs.str(); return lhs == rhs.str();
} }
[[nodiscard]] bool operator()(const std::string& lhs, const LiteralString& rhs) const { [[nodiscard]] bool operator()(const std::string& lhs, const LiteralString& rhs) const
{
return lhs == rhs.str(); return lhs == rhs.str();
} }
}; };
} } // namespace lms::core
+3 -2
View File
@@ -26,11 +26,12 @@
namespace std namespace std
{ {
template<> struct hash<boost::asio::ip::address> template<>
struct hash<boost::asio::ip::address>
{ {
std::size_t operator()(const boost::asio::ip::address& ipAddr) const; std::size_t operator()(const boost::asio::ip::address& ipAddr) const;
}; };
} } // namespace std
#endif // BOOST_ASIO_HAS_STD_HASH #endif // BOOST_ASIO_HAS_STD_HASH
+1 -1
View File
@@ -64,4 +64,4 @@ namespace lms::core::pathUtils
return longestCommonPath; return longestCommonPath;
} }
} } // namespace lms::core::pathUtils
+1 -1
View File
@@ -57,4 +57,4 @@ namespace lms::core::random
return std::next(std::begin(container), getRandom(0, static_cast<int>(container.size() - 1))); return std::next(std::begin(container), getRandom(0, static_cast<int>(container.size() - 1)));
} }
} } // namespace lms::core::random
@@ -48,4 +48,4 @@ namespace lms::core
std::mutex _sharedCountMutex; std::mutex _sharedCountMutex;
std::unordered_map<std::thread::id, std::size_t> _sharedCounts; std::unordered_map<std::thread::id, std::size_t> _sharedCounts;
}; };
} } // namespace lms::core
+1 -1
View File
@@ -70,4 +70,4 @@ namespace lms::core
static inline std::unique_ptr<Class> _service; static inline std::unique_ptr<Class> _service;
}; };
} } // namespace lms::core
+1 -1
View File
@@ -39,4 +39,4 @@ namespace lms::core::logging
std::ostream& _os; std::ostream& _os;
const EnumSet<Severity> _severities; const EnumSet<Severity> _severities;
}; };
} } // namespace lms::core::logging
+3 -3
View File
@@ -22,9 +22,9 @@
#include <initializer_list> #include <initializer_list>
#include <optional> #include <optional>
#include <span> #include <span>
#include <sstream>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <sstream>
#include <vector> #include <vector>
#define QUOTEME(x) QUOTEME_1(x) #define QUOTEME(x) QUOTEME_1(x)
@@ -34,7 +34,7 @@ namespace Wt
{ {
class WDate; class WDate;
class WDateTime; class WDateTime;
} } // namespace Wt
namespace lms::core::stringUtils namespace lms::core::stringUtils
{ {
@@ -100,4 +100,4 @@ namespace lms::core::stringUtils
[[nodiscard]] std::string toISO8601String(const Wt::WDateTime& dateTime); [[nodiscard]] std::string toISO8601String(const Wt::WDateTime& dateTime);
[[nodiscard]] std::string toISO8601String(const Wt::WDate& date); [[nodiscard]] std::string toISO8601String(const Wt::WDate& date);
} } // namespace lms::core::stringUtils
+11 -5
View File
@@ -26,24 +26,30 @@ namespace lms::core
namespace details namespace details
{ {
template<int... Is> template<int... Is>
struct Seq { }; struct Seq
{
};
template<int N, int... Is> template<int N, int... Is>
struct GenSeq : GenSeq<N - 1, N - 1, Is...> { }; struct GenSeq : GenSeq<N - 1, N - 1, Is...>
{
};
template<int... Is> template<int... Is>
struct GenSeq<0, Is...> : Seq<Is...> { }; struct GenSeq<0, Is...> : Seq<Is...>
{
};
template<typename T, typename Func, int... Is> template<typename T, typename Func, int... Is>
void forEachTypeInTuple(T&& t, Func f, Seq<Is...>) void forEachTypeInTuple(T&& t, Func f, Seq<Is...>)
{ {
auto l = { (f(std::get<Is>(t)), 0)... }; auto l = { (f(std::get<Is>(t)), 0)... };
} }
} } // namespace details
template<typename... Ts, typename Func> template<typename... Ts, typename Func>
void forEachTypeInTuple(std::tuple<Ts...> const& t, Func f) void forEachTypeInTuple(std::tuple<Ts...> const& t, Func f)
{ {
details::forEachTypeInTuple(t, f, details::GenSeq<sizeof...(Ts)>()); details::forEachTypeInTuple(t, f, details::GenSeq<sizeof...(Ts)>());
} }
} } // namespace lms::core
+1 -1
View File
@@ -41,7 +41,7 @@ namespace lms::core
UUID(std::string_view value); UUID(std::string_view value);
std::string _value; std::string _value;
}; };
} } // namespace lms::core
namespace lms::core::stringUtils namespace lms::core::stringUtils
{ {
+3 -2
View File
@@ -28,7 +28,8 @@ namespace lms::core::utils
constexpr T clamp(T v, T lo, T hi, Compare comp = {}) constexpr T clamp(T v, T lo, T hi, Compare comp = {})
{ {
assert(!comp(hi, lo)); assert(!comp(hi, lo));
return comp(v, lo) ? lo : comp(hi, v) ? hi : v; return comp(v, lo) ? lo : comp(hi, v) ? hi :
v;
} }
template<typename Container, typename T> template<typename Container, typename T>
@@ -38,4 +39,4 @@ namespace lms::core::utils
if (std::find(std::cbegin(container), std::cend(container), val) == std::cend(container)) if (std::find(std::cbegin(container), std::cend(container), val) == std::cend(container))
container.push_back(val); container.push_back(val);
} }
} } // namespace lms::core::utils
+1 -1
View File
@@ -37,4 +37,4 @@ namespace lms::core::logging
void processLog(const Log& log) override; void processLog(const Log& log) override;
const Severity _minSeverity; const Severity _minSeverity;
}; };
} } // namespace lms::core::logging
@@ -56,4 +56,4 @@ namespace lms::core::http
Wt::Http::Message message; Wt::Http::Message message;
}; };
} } // namespace lms::core::http
+2 -1
View File
@@ -20,6 +20,7 @@
#pragma once #pragma once
#include <string_view> #include <string_view>
#include <boost/asio/io_context.hpp> #include <boost/asio/io_context.hpp>
#include "core/http/ClientRequestParameters.hpp" #include "core/http/ClientRequestParameters.hpp"
@@ -36,4 +37,4 @@ namespace lms::core::http
}; };
std::unique_ptr<IClient> createClient(boost::asio::io_context& ioContext, std::string_view baseUrl); std::unique_ptr<IClient> createClient(boost::asio::io_context& ioContext, std::string_view baseUrl);
} } // namespace lms::core::http
+1 -1
View File
@@ -60,4 +60,4 @@ namespace lms::core
EXPECT_EQ(test, test2); EXPECT_EQ(test, test2);
} }
} }
} } // namespace lms::core
+2 -2
View File
@@ -18,6 +18,7 @@
*/ */
#include <unordered_map> #include <unordered_map>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "core/LiteralString.hpp" #include "core/LiteralString.hpp"
@@ -67,6 +68,5 @@ namespace lms::core
EXPECT_FALSE(myMap.contains(std::string{ "abcd" })); EXPECT_FALSE(myMap.contains(std::string{ "abcd" }));
EXPECT_FALSE(myMap.contains(std::string_view{ "abcd" })); EXPECT_FALSE(myMap.contains(std::string_view{ "abcd" }));
} }
}
} }
} // namespace lms::core
+4 -8
View File
@@ -32,8 +32,7 @@ namespace lms::core::pathUtils::tests
std::filesystem::path expectedCommonPath; std::filesystem::path expectedCommonPath;
}; };
TestCase tests[] TestCase tests[]{
{
{ "foo.txt", "/foo/foo.txt", "" }, { "foo.txt", "/foo/foo.txt", "" },
{ "/", "/file.txt", "/" }, { "/", "/file.txt", "/" },
{ "/foo/bar/file1.txt", "/foo/bar/file2.txt", "/foo/bar" }, { "/foo/bar/file1.txt", "/foo/bar/file2.txt", "/foo/bar" },
@@ -48,7 +47,6 @@ namespace lms::core::pathUtils::tests
} }
} }
TEST(Path, getLongestCommonPathIterator) TEST(Path, getLongestCommonPathIterator)
{ {
struct TestCase struct TestCase
@@ -57,8 +55,7 @@ namespace lms::core::pathUtils::tests
std::filesystem::path expectedCommonPath; std::filesystem::path expectedCommonPath;
}; };
TestCase tests[] TestCase tests[]{
{
{ {}, "" }, { {}, "" },
{ { "/" }, "/" }, { { "/" }, "/" },
{ { "/foo", "/bar" }, "/" }, { { "/foo", "/bar" }, "/" },
@@ -85,8 +82,7 @@ namespace lms::core::pathUtils::tests
bool expectedResult; bool expectedResult;
}; };
TestCase tests[] TestCase tests[]{
{
{ "/file.txt", "/", true }, { "/file.txt", "/", true },
{ "/root/folder/file.txt", "/root", true }, { "/root/folder/file.txt", "/root", true },
{ "/root/file.txt", "/root", true }, { "/root/file.txt", "/root", true },
@@ -105,4 +101,4 @@ namespace lms::core::pathUtils::tests
EXPECT_EQ(core::pathUtils::isPathInRootPath(test.path, test.rootPath), test.expectedResult) << "Failed: path = " << test.path << ", rootPath = " << test.rootPath; EXPECT_EQ(core::pathUtils::isPathInRootPath(test.path, test.rootPath), test.expectedResult) << "Failed: path = " << test.path << ", rootPath = " << test.rootPath;
} }
} }
} } // namespace lms::core::pathUtils::tests
+2 -3
View File
@@ -66,8 +66,7 @@ namespace lms::core
std::atomic<std::size_t> nbShared{}; std::atomic<std::size_t> nbShared{};
for (std::size_t i{}; i < nbThreads; ++i) for (std::size_t i{}; i < nbThreads; ++i)
{ {
threads.emplace_back([&] threads.emplace_back([&] {
{
{ {
std::unique_lock lock{ mutex }; std::unique_lock lock{ mutex };
@@ -102,4 +101,4 @@ namespace lms::core
for (std::thread& t : threads) for (std::thread& t : threads)
t.join(); t.join();
} }
} } // namespace lms::core
+9 -14
View File
@@ -19,9 +19,10 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <Wt/WDateTime.h>
#include <Wt/WDate.h> #include <Wt/WDate.h>
#include <Wt/WDateTime.h>
#include <Wt/WTime.h> #include <Wt/WTime.h>
#include "core/String.hpp" #include "core/String.hpp"
namespace lms::core::stringUtils::tests namespace lms::core::stringUtils::tests
@@ -35,8 +36,7 @@ namespace lms::core::stringUtils::tests
std::vector<std::string_view> expectedOutput; std::vector<std::string_view> expectedOutput;
}; };
TestCase tests[] TestCase tests[]{
{
{ "abc", '-', { "abc" } }, { "abc", '-', { "abc" } },
{ "a", '-', { "a" } }, { "a", '-', { "a" } },
{ "", '-', { "" } }, { "", '-', { "" } },
@@ -77,8 +77,7 @@ namespace lms::core::stringUtils::tests
std::vector<std::string_view> expectedOutput; std::vector<std::string_view> expectedOutput;
}; };
TestCase tests[] TestCase tests[]{
{
{ "abc", "", { "abc" } }, { "abc", "", { "abc" } },
{ "abc", "-", { "abc" } }, { "abc", "-", { "abc" } },
{ "abc", "b", { "a", "c" } }, { "abc", "b", { "a", "c" } },
@@ -108,8 +107,7 @@ namespace lms::core::stringUtils::tests
std::string expectedOutput; std::string expectedOutput;
}; };
TestCase tests[] TestCase tests[]{
{
{ { "a", "b", "c" }, "-", "a-b-c" }, { { "a", "b", "c" }, "-", "a-b-c" },
{ { "a", "b", "c" }, ",", "a,b,c" }, { { "a", "b", "c" }, ",", "a,b,c" },
{ { "a", "b", "c" }, "***", "a***b***c" }, { { "a", "b", "c" }, "***", "a***b***c" },
@@ -136,8 +134,7 @@ namespace lms::core::stringUtils::tests
std::string expectedOutput; std::string expectedOutput;
}; };
TestCase tests[] TestCase tests[]{
{
{ { "" }, ';', '\\', "" }, { { "" }, ';', '\\', "" },
{ { ";" }, ';', '\\', "\\;" }, { { ";" }, ';', '\\', "\\;" },
{ { ";;" }, ';', '\\', "\\;\\;" }, { { ";;" }, ';', '\\', "\\;\\;" },
@@ -162,8 +159,7 @@ namespace lms::core::stringUtils::tests
std::vector<std::string> expectedOutput; std::vector<std::string> expectedOutput;
}; };
TestCase tests[] TestCase tests[]{
{
{ "", ';', '\\', {} }, { "", ';', '\\', {} },
{ "\\;", ';', '\\', { ";" } }, { "\\;", ';', '\\', { ";" } },
{ "\\;\\;", ';', '\\', { ";;" } }, { "\\;\\;", ';', '\\', { ";;" } },
@@ -250,8 +246,7 @@ namespace lms::core::stringUtils::tests
std::string expectedOutput; std::string expectedOutput;
}; };
TestCase tests[] TestCase tests[]{
{
{ "", "" }, { "", "" },
{ "C", "C" }, { "C", "C" },
{ "c", "C" }, { "c", "C" },
@@ -294,4 +289,4 @@ namespace lms::core::stringUtils::tests
EXPECT_FALSE(stringEndsWith("FooBar", "1FooBar")); EXPECT_FALSE(stringEndsWith("FooBar", "1FooBar"));
EXPECT_FALSE(stringEndsWith("FooBar", "R")); EXPECT_FALSE(stringEndsWith("FooBar", "R"));
} }
} } // namespace lms::core::stringUtils::tests
+3 -3
View File
@@ -19,6 +19,7 @@
#include <sstream> #include <sstream>
#include <thread> #include <thread>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "core/ITraceLogger.hpp" #include "core/ITraceLogger.hpp"
@@ -33,8 +34,7 @@ namespace lms::core::tracing::tests
std::vector<std::thread> threads; std::vector<std::thread> threads;
for (std::size_t i{}; i < 16; ++i) for (std::size_t i{}; i < 16; ++i)
{ {
threads.emplace_back([&] threads.emplace_back([&] {
{
ScopedTrace loggedEvent{ "MyCategory", Level::Overview, "MyEventLogged", "SomeArgType", "SomeArg", traceLogger.get() }; ScopedTrace loggedEvent{ "MyCategory", Level::Overview, "MyEventLogged", "SomeArgType", "SomeArg", traceLogger.get() };
ScopedTrace notLoggedEvent{ "MyNotLoggedCategory", Level::Detailed, "MyEventNotLogged", "SomeNotLoggedArgType", "SomeNotLoggedArg", traceLogger.get() }; ScopedTrace notLoggedEvent{ "MyNotLoggedCategory", Level::Detailed, "MyEventNotLogged", "SomeNotLoggedArgType", "SomeNotLoggedArg", traceLogger.get() };
}); });
@@ -56,4 +56,4 @@ namespace lms::core::tracing::tests
EXPECT_EQ(oss.str().find("SomeNotLoggedArgType"), std::string::npos); EXPECT_EQ(oss.str().find("SomeNotLoggedArgType"), std::string::npos);
EXPECT_EQ(oss.str().find("SomeNotLoggedArg"), std::string::npos); EXPECT_EQ(oss.str().find("SomeNotLoggedArg"), std::string::npos);
} }
} } // namespace lms::core::tracing::tests
+1 -1
View File
@@ -37,4 +37,4 @@ namespace lms::core
EXPECT_TRUE(uuid1 >= uuid2); EXPECT_TRUE(uuid1 >= uuid2);
EXPECT_TRUE(uuid1 <= uuid2); EXPECT_TRUE(uuid1 <= uuid2);
} }
} } // namespace lms::core
-1
View File
@@ -24,4 +24,3 @@ int main(int argc, char **argv)
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }
+22 -29
View File
@@ -20,16 +20,17 @@
#include <Wt/Dbo/WtSqlTraits.h> #include <Wt/Dbo/WtSqlTraits.h>
#include "core/ILogger.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "database/Release.hpp" #include "database/Release.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "core/ILogger.hpp"
#include "SqlQuery.hpp"
#include "Utils.hpp"
#include "EnumSetTraits.hpp" #include "EnumSetTraits.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "SqlQuery.hpp"
#include "Utils.hpp"
namespace lms::db namespace lms::db
{ {
@@ -97,15 +98,19 @@ namespace lms::db
{ {
assert(params.feedbackBackend); assert(params.feedbackBackend);
query.join("starred_artist s_a ON s_a.artist_id = a.id") query.join("starred_artist s_a ON s_a.artist_id = a.id")
.where("s_a.user_id = ?").bind(params.starringUser) .where("s_a.user_id = ?")
.where("s_a.backend = ?").bind(*params.feedbackBackend) .bind(params.starringUser)
.where("s_a.sync_state <> ?").bind(SyncState::PendingRemove); .where("s_a.backend = ?")
.bind(*params.feedbackBackend)
.where("s_a.sync_state <> ?")
.bind(SyncState::PendingRemove);
} }
if (params.clusters.size() == 1) if (params.clusters.size() == 1)
{ {
query.join("track_cluster t_c ON t_c.track_id = t_a_l.track_id") query.join("track_cluster t_c ON t_c.track_id = t_a_l.track_id")
.where("t_c.cluster_id = ?").bind(params.clusters.front()); .where("t_c.cluster_id = ?")
.bind(params.clusters.front());
} }
else if (params.clusters.size() > 1) else if (params.clusters.size() > 1)
{ {
@@ -173,12 +178,12 @@ namespace lms::db
return createQuery<ResultType>(session, itemToSelect, params); return createQuery<ResultType>(session, itemToSelect, params);
} }
} } // namespace
Artist::Artist(const std::string& name, const std::optional<core::UUID>& MBID) Artist::Artist(const std::string& name, const std::optional<core::UUID>& MBID)
: _name{ std::string(name, 0 , _maxNameLength) }, : _name{ std::string(name, 0, _maxNameLength) }
_sortName{ _name }, , _sortName{ _name }
_MBID{ MBID ? MBID->getAsString() : "" } , _MBID{ MBID ? MBID->getAsString() : "" }
{ {
} }
@@ -198,10 +203,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Artist>>("SELECT a FROM artist a") auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Artist>>("SELECT a FROM artist a").orderBy("a.id").where("a.id > ?").bind(lastRetrievedArtist).limit(static_cast<int>(count)) };
.orderBy("a.id")
.where("a.id > ?").bind(lastRetrievedArtist)
.limit(static_cast<int>(count)) };
if (library.isValid()) if (library.isValid())
{ {
@@ -209,8 +211,7 @@ namespace lms::db
query.where("EXISTS (SELECT 1 FROM track_artist_link t_a_l JOIN track t ON t.id = t_a_l.track_id WHERE t_a_l.artist_id = a.id AND t.media_library_id = ?)").bind(library); query.where("EXISTS (SELECT 1 FROM track_artist_link t_a_l JOIN track t ON t.id = t_a_l.track_id WHERE t_a_l.artist_id = a.id AND t.media_library_id = ?)").bind(library);
} }
utils::forEachQueryResult(query, [&](const Artist::pointer& artist) utils::forEachQueryResult(query, [&](const Artist::pointer& artist) {
{
func(artist); func(artist);
lastRetrievedArtist = artist->getId(); lastRetrievedArtist = artist->getId();
}); });
@@ -220,9 +221,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQueryResults<Artist::pointer>(session.getDboSession()->find<Artist>() return utils::fetchQueryResults<Artist::pointer>(session.getDboSession()->find<Artist>().where("name = ?").bind(std::string{ name, 0, _maxNameLength }).orderBy("LENGTH(mbid) DESC")); // put mbid entries first
.where("name = ?").bind(std::string{ name, 0, _maxNameLength })
.orderBy("LENGTH(mbid) DESC")); // put mbid entries first
} }
Artist::pointer Artist::find(Session& session, const core::UUID& mbid) Artist::pointer Artist::find(Session& session, const core::UUID& mbid)
@@ -279,8 +278,7 @@ namespace lms::db
assert(session()); assert(session());
std::ostringstream oss; std::ostringstream oss;
oss << oss << "SELECT a.id FROM artist a"
"SELECT a.id FROM artist a"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id" " INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
" INNER JOIN track t ON t.id = t_a_l.track_id" " INNER JOIN track t ON t.id = t_a_l.track_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id" " INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
@@ -309,11 +307,7 @@ namespace lms::db
oss << ")"; oss << ")";
} }
auto query{ session()->query<ArtistId>(oss.str()) auto query{ session()->query<ArtistId>(oss.str()).bind(getId()).bind(getId()).groupBy("a.id").orderBy("COUNT(*) DESC, RANDOM()") };
.bind(getId())
.bind(getId())
.groupBy("a.id")
.orderBy("COUNT(*) DESC, RANDOM()") };
for (const TrackArtistLinkType type : artistLinkTypes) for (const TrackArtistLinkType type : artistLinkTypes)
query.bind(type); query.bind(type);
@@ -347,8 +341,7 @@ namespace lms::db
query.bind(bindArg); query.bind(bindArg);
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType; std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType;
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) {
{
if (clustersByType[cluster->getType()->getId()].size() < size) if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster); clustersByType[cluster->getType()->getId()].push_back(cluster);
}); });
+4 -2
View File
@@ -20,10 +20,12 @@
#include "database/AuthToken.hpp" #include "database/AuthToken.hpp"
#include <Wt/Dbo/WtSqlTraits.h> #include <Wt/Dbo/WtSqlTraits.h>
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "StringViewTraits.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "StringViewTraits.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace lms::db namespace lms::db
@@ -53,4 +55,4 @@ namespace lms::db
return utils::fetchQuerySingleResult(session.getDboSession()->find<AuthToken>().where("value = ?").bind(value)); return utils::fetchQuerySingleResult(session.getDboSession()->find<AuthToken>().where("value = ?").bind(value));
} }
} } // namespace lms::db
+10 -16
View File
@@ -25,9 +25,10 @@
#include "database/ScanSettings.hpp" #include "database/ScanSettings.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "StringViewTraits.hpp"
#include "SqlQuery.hpp" #include "SqlQuery.hpp"
#include "StringViewTraits.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace lms::db namespace lms::db
@@ -91,11 +92,11 @@ namespace lms::db
return createQuery<ResultType>(session, itemToSelect, params); return createQuery<ResultType>(session, itemToSelect, params);
} }
} } // namespace
Cluster::Cluster(ObjectPtr<ClusterType> type, std::string_view name) Cluster::Cluster(ObjectPtr<ClusterType> type, std::string_view name)
: _name{ std::string {name, 0, _maxNameLength} }, : _name{ std::string{ name, 0, _maxNameLength } }
_clusterType{ getDboPtr(type) } , _clusterType{ getDboPtr(type) }
{ {
} }
@@ -154,16 +155,14 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN track_cluster t_c ON t_c.track_id = t.id") return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("t_c.cluster_id = ?").bind(id));
.where("t_c.cluster_id = ?").bind(id));
} }
std::size_t Cluster::computeReleaseCount(Session& session, ClusterId id) std::size_t Cluster::computeReleaseCount(Session& session, ClusterId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(DISTINCT r.id) FROM release r INNER JOIN track t on t.release_id = r.id INNER JOIN track_cluster t_c ON t_c.track_id = t.id") return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(DISTINCT r.id) FROM release r INNER JOIN track t on t.release_id = r.id INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("t_c.cluster_id = ?").bind(id));
.where("t_c.cluster_id = ?").bind(id));
} }
void Cluster::addTrack(ObjectPtr<Track> track) void Cluster::addTrack(ObjectPtr<Track> track)
@@ -175,8 +174,7 @@ namespace lms::db
{ {
assert(session()); assert(session());
auto query{ session()->query<TrackId>("SELECT t.id FROM track t INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id") auto query{ session()->query<TrackId>("SELECT t.id FROM track t INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("c.id = ?").bind(getId()) };
.where("c.id = ?").bind(getId()) };
return utils::execRangeQuery<TrackId>(query, range); return utils::execRangeQuery<TrackId>(query, range);
} }
@@ -255,9 +253,7 @@ namespace lms::db
assert(self()); assert(self());
assert(session()); assert(session());
return utils::fetchQuerySingleResult(session()->find<Cluster>() return utils::fetchQuerySingleResult(session()->find<Cluster>().where("name = ?").bind(name).where("cluster_type_id = ?").bind(getId()));
.where("name = ?").bind(name)
.where("cluster_type_id = ?").bind(getId()));
} }
std::vector<Cluster::pointer> ClusterType::getClusters() const std::vector<Cluster::pointer> ClusterType::getClusters() const
@@ -265,8 +261,6 @@ namespace lms::db
assert(self()); assert(self());
assert(session()); assert(session());
return utils::fetchQueryResults<Cluster::pointer>(session()->find<Cluster>() return utils::fetchQueryResults<Cluster::pointer>(session()->find<Cluster>().where("cluster_type_id = ?").bind(getId()).orderBy("name"));
.where("cluster_type_id = ?").bind(getId())
.orderBy("name"));
} }
} // namespace lms::db } // namespace lms::db
+3 -3
View File
@@ -22,12 +22,12 @@
#include <Wt/Dbo/FixedSqlConnectionPool.h> #include <Wt/Dbo/FixedSqlConnectionPool.h>
#include <Wt/Dbo/backend/Sqlite3.h> #include <Wt/Dbo/backend/Sqlite3.h>
#include "database/Session.hpp"
#include "database/User.hpp"
#include "core/IConfig.hpp" #include "core/IConfig.hpp"
#include "core/ILogger.hpp" #include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp" #include "core/ITraceLogger.hpp"
#include "core/Service.hpp" #include "core/Service.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
namespace lms::db namespace lms::db
{ {
@@ -68,7 +68,7 @@ namespace lms::db
std::filesystem::path _dbPath; std::filesystem::path _dbPath;
}; };
} } // namespace
// Session living class handling the database and the login // Session living class handling the database and the login
Db::Db(const std::filesystem::path& dbPath, std::size_t connectionCount) Db::Db(const std::filesystem::path& dbPath, std::size_t connectionCount)
+2 -2
View File
@@ -20,6 +20,7 @@
#pragma once #pragma once
#include <type_traits> #include <type_traits>
#include <Wt/Dbo/StdSqlTraits.h> #include <Wt/Dbo/StdSqlTraits.h>
#include "core/EnumSet.hpp" #include "core/EnumSet.hpp"
@@ -49,5 +50,4 @@ namespace Wt::Dbo
return false; return false;
} }
}; };
} } // namespace Wt::Dbo
+2 -2
View File
@@ -20,6 +20,7 @@
#pragma once #pragma once
#include <type_traits> #include <type_traits>
#include <Wt/Dbo/StdSqlTraits.h> #include <Wt/Dbo/StdSqlTraits.h>
#include "database/Types.hpp" #include "database/Types.hpp"
@@ -55,5 +56,4 @@ namespace Wt::Dbo
return false; return false;
} }
}; };
} } // namespace Wt::Dbo
+22 -40
View File
@@ -21,6 +21,7 @@
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "SqlQuery.hpp" #include "SqlQuery.hpp"
#include "Utils.hpp" #include "Utils.hpp"
@@ -31,9 +32,7 @@ namespace lms::db
{ {
Wt::Dbo::Query<ArtistId> createArtistsQuery(Session& session, const Listen::ArtistStatsFindParameters& params) Wt::Dbo::Query<ArtistId> createArtistsQuery(Session& session, const Listen::ArtistStatsFindParameters& params)
{ {
auto query{ session.getDboSession()->query<ArtistId>("SELECT a.id from artist a") auto query{ session.getDboSession()->query<ArtistId>("SELECT a.id from artist a").join("track_artist_link t_a_l ON t_a_l.artist_id = a.id").join("listen l ON l.track_id = t_a_l.track_id") };
.join("track_artist_link t_a_l ON t_a_l.artist_id = a.id")
.join("listen l ON l.track_id = t_a_l.track_id") };
if (params.user.isValid()) if (params.user.isValid())
query.where("l.user_id = ?").bind(params.user); query.where("l.user_id = ?").bind(params.user);
@@ -96,9 +95,7 @@ namespace lms::db
Wt::Dbo::Query<ReleaseId> createReleasesQuery(Session& session, const Listen::StatsFindParameters& params) Wt::Dbo::Query<ReleaseId> createReleasesQuery(Session& session, const Listen::StatsFindParameters& params)
{ {
auto query{ session.getDboSession()->query<ReleaseId>("SELECT r.id from release r") auto query{ session.getDboSession()->query<ReleaseId>("SELECT r.id from release r").join("track t ON t.release_id = r.id").join("listen l ON l.track_id = t.id") };
.join("track t ON t.release_id = r.id")
.join("listen l ON l.track_id = t.id") };
if (params.user.isValid()) if (params.user.isValid())
query.where("l.user_id = ?").bind(params.user); query.where("l.user_id = ?").bind(params.user);
@@ -109,7 +106,8 @@ namespace lms::db
if (params.artist.isValid()) if (params.artist.isValid())
{ {
query.join("track_artist_link t_a_l ON t_a_l.track_id = t.id") query.join("track_artist_link t_a_l ON t_a_l.track_id = t.id")
.where("t_a_l.artist_id = ?").bind(params.artist); .where("t_a_l.artist_id = ?")
.bind(params.artist);
} }
if (params.library.isValid()) if (params.library.isValid())
@@ -144,8 +142,7 @@ namespace lms::db
Wt::Dbo::Query<TrackId> createTracksQuery(Session& session, const Listen::StatsFindParameters& params) Wt::Dbo::Query<TrackId> createTracksQuery(Session& session, const Listen::StatsFindParameters& params)
{ {
auto query{ session.getDboSession()->query<TrackId>("SELECT t.id from track t") auto query{ session.getDboSession()->query<TrackId>("SELECT t.id from track t").join("listen l ON l.track_id = t.id") };
.join("listen l ON l.track_id = t.id") };
if (params.user.isValid()) if (params.user.isValid())
query.where("l.user_id = ?").bind(params.user); query.where("l.user_id = ?").bind(params.user);
@@ -156,7 +153,8 @@ namespace lms::db
if (params.artist.isValid()) if (params.artist.isValid())
{ {
query.join("track_artist_link t_a_l ON t_a_l.track_id = t.id") query.join("track_artist_link t_a_l ON t_a_l.track_id = t.id")
.where("t_a_l.artist_id = ?").bind(params.artist); .where("t_a_l.artist_id = ?")
.bind(params.artist);
} }
if (params.library.isValid()) if (params.library.isValid())
@@ -187,14 +185,15 @@ namespace lms::db
return query; return query;
} }
} } // namespace
Listen::Listen(ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime) Listen::Listen(ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime)
: _dateTime{ Wt::WDateTime::fromTime_t(dateTime.toTime_t()) } : _dateTime{ Wt::WDateTime::fromTime_t(dateTime.toTime_t()) }
, _backend{ backend } , _backend{ backend }
, _user{ getDboPtr(user) } , _user{ getDboPtr(user) }
, _track{ getDboPtr(track) } , _track{ getDboPtr(track) }
{} {
}
Listen::pointer Listen::create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime) Listen::pointer Listen::create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime)
{ {
@@ -218,8 +217,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession()->query<ListenId>("SELECT id FROM listen") auto query{ session.getDboSession()->query<ListenId>("SELECT id FROM listen").orderBy("date_time") };
.orderBy("date_time") };
if (parameters.user.isValid()) if (parameters.user.isValid())
query.where("user_id = ?").bind(parameters.user); query.where("user_id = ?").bind(parameters.user);
@@ -237,11 +235,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<Listen>() return utils::fetchQuerySingleResult(session.getDboSession()->find<Listen>().where("user_id = ?").bind(userId).where("track_id = ?").bind(trackId).where("backend = ?").bind(backend).where("date_time = ?").bind(Wt::WDateTime::fromTime_t(dateTime.toTime_t())));
.where("user_id = ?").bind(userId)
.where("track_id = ?").bind(trackId)
.where("backend = ?").bind(backend)
.where("date_time = ?").bind(Wt::WDateTime::fromTime_t(dateTime.toTime_t())));
} }
RangeResults<ArtistId> Listen::getTopArtists(Session& session, const ArtistStatsFindParameters& params) RangeResults<ArtistId> Listen::getTopArtists(Session& session, const ArtistStatsFindParameters& params)
@@ -280,7 +274,8 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createArtistsQuery(session, params) auto query{ createArtistsQuery(session, params)
.groupBy("a.id").having("l.date_time = MAX(l.date_time)") .groupBy("a.id")
.having("l.date_time = MAX(l.date_time)")
.orderBy("l.date_time DESC") }; .orderBy("l.date_time DESC") };
return utils::execRangeQuery<ArtistId>(query, params.range); return utils::execRangeQuery<ArtistId>(query, params.range);
@@ -290,7 +285,8 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createReleasesQuery(session, params) auto query{ createReleasesQuery(session, params)
.groupBy("r.id").having("l.date_time = MAX(l.date_time)") .groupBy("r.id")
.having("l.date_time = MAX(l.date_time)")
.orderBy("l.date_time DESC") }; .orderBy("l.date_time DESC") };
return utils::execRangeQuery<ReleaseId>(query, params.range); return utils::execRangeQuery<ReleaseId>(query, params.range);
@@ -300,7 +296,8 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createTracksQuery(session, params) auto query{ createTracksQuery(session, params)
.groupBy("t.id").having("l.date_time = MAX(l.date_time)") .groupBy("t.id")
.having("l.date_time = MAX(l.date_time)")
.orderBy("l.date_time DESC") }; .orderBy("l.date_time DESC") };
return utils::execRangeQuery<TrackId>(query, params.range); return utils::execRangeQuery<TrackId>(query, params.range);
@@ -310,11 +307,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(*) from listen l") return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(*) 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"));
.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"));
} }
std::size_t Listen::getCount(Session& session, UserId userId, ReleaseId releaseId) std::size_t Listen::getCount(Session& session, UserId userId, ReleaseId releaseId)
@@ -339,24 +332,13 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
// TODO not pending remove? // TODO not pending remove?
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l") 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));
.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));
} }
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId trackId) Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId trackId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
// TODO not pending remove? // TODO not pending remove?
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l") return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l").where("l.track_id = ?").bind(trackId).where("l.user_id = ?").bind(userId).where("l.backend = ?").bind(backend).orderBy("l.date_time DESC").limit(1));
.where("l.track_id = ?").bind(trackId)
.where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend)
.orderBy("l.date_time DESC")
.limit(1));
} }
} // namespace lms::db } // namespace lms::db
+4 -4
View File
@@ -22,6 +22,7 @@
#include "database/ScanSettings.hpp" #include "database/ScanSettings.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "PathTraits.hpp" #include "PathTraits.hpp"
#include "StringViewTraits.hpp" #include "StringViewTraits.hpp"
@@ -30,8 +31,8 @@
namespace lms::db namespace lms::db
{ {
MediaLibrary::MediaLibrary(const std::filesystem::path& p, std::string_view name) MediaLibrary::MediaLibrary(const std::filesystem::path& p, std::string_view name)
: _path{ p }, : _path{ p }
_name{ std::string {name, 0, maxNameLength} } , _name{ std::string{ name, 0, maxNameLength } }
{ {
} }
@@ -72,8 +73,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
utils::forEachQueryResult(session.getDboSession()->find<MediaLibrary>(), [&](const MediaLibrary::pointer& mediaLibrary) utils::forEachQueryResult(session.getDboSession()->find<MediaLibrary>(), [&](const MediaLibrary::pointer& mediaLibrary) {
{
func(mediaLibrary); func(mediaLibrary);
}); });
} }
+14 -10
View File
@@ -21,13 +21,14 @@
#include <Wt/Dbo/WtSqlTraits.h> #include <Wt/Dbo/WtSqlTraits.h>
#include "core/Exception.hpp"
#include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp"
#include "database/Db.hpp" #include "database/Db.hpp"
#include "database/ScanSettings.hpp" #include "database/ScanSettings.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "core/Exception.hpp"
#include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace lms::db namespace lms::db
@@ -39,7 +40,8 @@ namespace lms::db
VersionInfo::VersionInfo() VersionInfo::VersionInfo()
: _version{ LMS_DATABASE_VERSION } : _version{ LMS_DATABASE_VERSION }
{} {
}
VersionInfo::pointer VersionInfo::getOrCreate(Session& session) VersionInfo::pointer VersionInfo::getOrCreate(Session& session)
{ {
@@ -58,14 +60,15 @@ namespace lms::db
return utils::fetchQuerySingleResult(session.getDboSession()->find<VersionInfo>()); return utils::fetchQuerySingleResult(session.getDboSession()->find<VersionInfo>());
} }
} } // namespace lms::db
namespace lms::db::Migration namespace lms::db::Migration
{ {
class ScopedNoForeignKeys class ScopedNoForeignKeys
{ {
public: public:
ScopedNoForeignKeys(Db& db) : _db{ db } ScopedNoForeignKeys(Db& db)
: _db{ db }
{ {
_db.executeSql("PRAGMA foreign_keys=OFF"); _db.executeSql("PRAGMA foreign_keys=OFF");
} }
@@ -73,6 +76,7 @@ namespace lms::db::Migration
{ {
_db.executeSql("PRAGMA foreign_keys=ON"); _db.executeSql("PRAGMA foreign_keys=ON");
} }
private: private:
ScopedNoForeignKeys(const ScopedNoForeignKeys&) = delete; ScopedNoForeignKeys(const ScopedNoForeignKeys&) = delete;
ScopedNoForeignKeys(ScopedNoForeignKeys&&) = delete; ScopedNoForeignKeys(ScopedNoForeignKeys&&) = delete;
@@ -330,7 +334,8 @@ CREATE TABLE IF NOT EXISTS "track_backup" (
session.getDboSession()->execute(R"(INSERT INTO "media_library" ("id", "version", "path", "name") session.getDboSession()->execute(R"(INSERT INTO "media_library" ("id", "version", "path", "name")
SELECT 1, 0, s_s.media_directory, "Main" SELECT 1, 0, s_s.media_directory, "Main"
FROM scan_settings s_s FROM scan_settings s_s
WHERE id = ?)").bind(scanSettingsId); WHERE id = ?)")
.bind(scanSettingsId);
// Remove the outdated column in scan_settings // Remove the outdated column in scan_settings
session.getDboSession()->execute("ALTER TABLE scan_settings DROP media_directory"); session.getDboSession()->execute("ALTER TABLE scan_settings DROP media_directory");
@@ -479,8 +484,7 @@ SELECT
using MigrationFunction = std::function<void(Session&)>; using MigrationFunction = std::function<void(Session&)>;
const std::map<unsigned, MigrationFunction> migrationFunctions const std::map<unsigned, MigrationFunction> migrationFunctions{
{
{ 33, migrateFromV33 }, { 33, migrateFromV33 },
{ 34, migrateFromV34 }, { 34, migrateFromV34 },
{ 35, migrateFromV35 }, { 35, migrateFromV35 },
@@ -550,4 +554,4 @@ SELECT
return migrationPerformed; return migrationPerformed;
} }
} } // namespace lms::db::Migration
+1 -1
View File
@@ -54,4 +54,4 @@ namespace lms::db
{ {
bool doDbMigration(Session& session); // return true if migration was performed bool doDbMigration(Session& session); // return true if migration was performed
} }
} } // namespace lms::db
+3 -3
View File
@@ -19,8 +19,9 @@
#pragma once #pragma once
#include <string>
#include <filesystem> #include <filesystem>
#include <string>
#include <Wt/Dbo/SqlTraits.h> #include <Wt/Dbo/SqlTraits.h>
namespace Wt::Dbo namespace Wt::Dbo
@@ -50,5 +51,4 @@ namespace Wt::Dbo
return true; return true;
} }
}; };
} } // namespace Wt::Dbo
+39 -63
View File
@@ -21,15 +21,16 @@
#include <Wt/Dbo/WtSqlTraits.h> #include <Wt/Dbo/WtSqlTraits.h>
#include "core/ILogger.hpp"
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "core/ILogger.hpp"
#include "SqlQuery.hpp"
#include "EnumSetTraits.hpp" #include "EnumSetTraits.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "SqlQuery.hpp"
#include "StringViewTraits.hpp" #include "StringViewTraits.hpp"
#include "Utils.hpp" #include "Utils.hpp"
@@ -63,7 +64,8 @@ namespace lms::db
{ {
query.join("release_release_type r_r_t ON r_r_t.release_id = r.id"); query.join("release_release_type r_r_t ON r_r_t.release_id = r.id");
query.join("release_type r_t ON r_t.id = r_r_t.release_type_id") query.join("release_type r_t ON r_t.id = r_r_t.release_type_id")
.where("r_t.name = ?").bind(params.releaseType); .where("r_t.name = ?")
.bind(params.releaseType);
} }
if (params.writtenAfter.isValid()) if (params.writtenAfter.isValid())
@@ -82,9 +84,12 @@ namespace lms::db
{ {
assert(params.feedbackBackend); assert(params.feedbackBackend);
query.join("starred_release s_r ON s_r.release_id = r.id") query.join("starred_release s_r ON s_r.release_id = r.id")
.where("s_r.user_id = ?").bind(params.starringUser) .where("s_r.user_id = ?")
.where("s_r.backend = ?").bind(*params.feedbackBackend) .bind(params.starringUser)
.where("s_r.sync_state <> ?").bind(SyncState::PendingRemove); .where("s_r.backend = ?")
.bind(*params.feedbackBackend)
.where("s_r.sync_state <> ?")
.bind(SyncState::PendingRemove);
} }
if (params.artist.isValid() if (params.artist.isValid()
@@ -143,7 +148,8 @@ namespace lms::db
if (params.clusters.size() == 1) if (params.clusters.size() == 1)
{ {
query.join("track_cluster t_c ON t_c.track_id = t.id") query.join("track_cluster t_c ON t_c.track_id = t.id")
.where("t_c.cluster_id = ?").bind(params.clusters.front()); .where("t_c.cluster_id = ?")
.bind(params.clusters.front());
} }
else if (params.clusters.size() > 1) else if (params.clusters.size() > 1)
{ {
@@ -200,7 +206,7 @@ namespace lms::db
return query; return query;
} }
} } // namespace
ReleaseType::ReleaseType(std::string_view name) ReleaseType::ReleaseType(std::string_view name)
: _name{ std::string(name, 0, _maxNameLength) } : _name{ std::string(name, 0, _maxNameLength) }
@@ -216,21 +222,19 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>() return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>().where("id = ?").bind(id));
.where("id = ?").bind(id));
} }
ReleaseType::pointer ReleaseType::find(Session& session, std::string_view name) ReleaseType::pointer ReleaseType::find(Session& session, std::string_view name)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>() return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>().where("name = ?").bind(name));
.where("name = ?").bind(name));
} }
Release::Release(const std::string& name, const std::optional<core::UUID>& MBID) Release::Release(const std::string& name, const std::optional<core::UUID>& MBID)
: _name{ std::string(name, 0 , _maxNameLength) }, : _name{ std::string(name, 0, _maxNameLength) }
_MBID{ MBID ? MBID->getAsString() : "" } , _MBID{ MBID ? MBID->getAsString() : "" }
{ {
} }
@@ -243,26 +247,21 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQueryResults<Release::pointer>(session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT DISTINCT r from release r") return utils::fetchQueryResults<Release::pointer>(session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT DISTINCT r from release r").join("track t ON t.release_id = r.id").where("r.name = ?").bind(std::string(name, 0, _maxNameLength)).where("t.absolute_file_path LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind(utils::escapeLikeKeyword(releaseDirectory.string()) + "%"));
.join("track t ON t.release_id = r.id")
.where("r.name = ?").bind(std::string(name, 0, _maxNameLength))
.where("t.absolute_file_path LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind(utils::escapeLikeKeyword(releaseDirectory.string()) + "%"));
} }
Release::pointer Release::find(Session& session, const core::UUID& mbid) Release::pointer Release::find(Session& session, const core::UUID& mbid)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>() return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>().where("mbid = ?").bind(mbid.getAsString()));
.where("mbid = ?").bind(mbid.getAsString()));
} }
Release::pointer Release::find(Session& session, ReleaseId id) Release::pointer Release::find(Session& session, ReleaseId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>() return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>().where("id = ?").bind(id));
.where("id = ?").bind(id));
} }
bool Release::exists(Session& session, ReleaseId id) bool Release::exists(Session& session, ReleaseId id)
@@ -290,10 +289,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT r FROM release r") auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT r FROM release r").orderBy("r.id").where("r.id > ?").bind(lastRetrievedRelease).limit(static_cast<int>(count)) };
.orderBy("r.id")
.where("r.id > ?").bind(lastRetrievedRelease)
.limit(static_cast<int>(count)) };
if (library.isValid()) if (library.isValid())
{ {
@@ -301,8 +297,7 @@ namespace lms::db
query.where("EXISTS (SELECT 1 FROM track t WHERE t.release_id = r.id AND t.media_library_id = ?)").bind(library); query.where("EXISTS (SELECT 1 FROM track t WHERE t.release_id = r.id AND t.media_library_id = ?)").bind(library);
} }
utils::forEachQueryResult(query, [&](const Release::pointer& release) utils::forEachQueryResult(query, [&](const Release::pointer& release) {
{
func(release); func(release);
lastRetrievedRelease = release->getId(); lastRetrievedRelease = release->getId();
}); });
@@ -342,8 +337,7 @@ namespace lms::db
std::size_t Release::getDiscCount() const std::size_t Release::getDiscCount() const
{ {
assert(session()); assert(session());
int res{ utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(DISTINCT disc_number) FROM track t") int res{ utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(DISTINCT disc_number) FROM track t").where("t.release_id = ?").bind(getId())) };
.where("t.release_id = ?").bind(getId()))};
return res; return res;
} }
@@ -352,13 +346,10 @@ namespace lms::db
assert(session()); assert(session());
using ResultType = std::tuple<int, std::string>; using ResultType = std::tuple<int, std::string>;
const auto query{ session()->query<ResultType>("SELECT DISTINCT disc_number, disc_subtitle FROM track t") const auto query{ session()->query<ResultType>("SELECT DISTINCT disc_number, disc_subtitle FROM track t").where("t.release_id = ?").bind(getId()).orderBy("disc_number") };
.where("t.release_id = ?").bind(getId())
.orderBy("disc_number")};
std::vector<DiscInfo> discs; std::vector<DiscInfo> discs;
utils::forEachQueryResult(query, [&](ResultType&& res) utils::forEachQueryResult(query, [&](ResultType&& res) {
{
discs.emplace_back(DiscInfo{ static_cast<std::size_t>(std::get<int>(res)), std::move(std::get<std::string>(res)) }); discs.emplace_back(DiscInfo{ static_cast<std::size_t>(std::get<int>(res)), std::move(std::get<std::string>(res)) });
}); });
@@ -380,10 +371,7 @@ namespace lms::db
assert(session()); assert(session());
const char* field{ original ? "original_date" : "date" }; const char* field{ original ? "original_date" : "date" };
auto query{ (session()->query<Wt::WDate>(std::string {"SELECT "} + "t." + field + " FROM track t") auto query{ (session()->query<Wt::WDate>(std::string{ "SELECT " } + "t." + field + " FROM track t").where("t.release_id = ?").groupBy(field).bind(getId())) };
.where("t.release_id = ?")
.groupBy(field)
.bind(getId())) };
const auto dates{ utils::fetchQueryResults(query) }; const auto dates{ utils::fetchQueryResults(query) };
@@ -409,9 +397,7 @@ namespace lms::db
assert(session()); assert(session());
const char* field{ original ? "original_year" : "year" }; const char* field{ original ? "original_year" : "year" };
auto query{ session()->query<std::optional<int>>(std::string {"SELECT "} + "t." + field + " FROM track t") auto query{ session()->query<std::optional<int>>(std::string{ "SELECT " } + "t." + field + " FROM track t").where("t.release_id = ?").bind(getId()).groupBy(field) };
.where("t.release_id = ?").bind(getId())
.groupBy(field) };
const auto years{ utils::fetchQueryResults(query) }; const auto years{ utils::fetchQueryResults(query) };
@@ -427,10 +413,7 @@ namespace lms::db
{ {
assert(session()); assert(session());
auto query{ session()->query<std::string>("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id") auto query{ session()->query<std::string>("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").groupBy("copyright").bind(getId()) };
.where("r.id = ?")
.groupBy("copyright")
.bind(getId()) };
const auto copyrights{ utils::fetchQueryResults(query) }; const auto copyrights{ utils::fetchQueryResults(query) };
@@ -445,10 +428,7 @@ namespace lms::db
{ {
assert(session()); assert(session());
const auto query{ session()->query<std::string> const auto query{ session()->query<std::string>("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").bind(getId()).groupBy("copyright_url") };
("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id")
.where("r.id = ?").bind(getId())
.groupBy("copyright_url") };
const auto copyrights{ utils::fetchQueryResults(query) }; const auto copyrights{ utils::fetchQueryResults(query) };
@@ -463,9 +443,7 @@ namespace lms::db
{ {
assert(session()); assert(session());
return utils::fetchQuerySingleResult(session()->query<int>("SELECT COALESCE(AVG(t.bitrate), 0) FROM track t") return utils::fetchQuerySingleResult(session()->query<int>("SELECT COALESCE(AVG(t.bitrate), 0) FROM track t").where("release_id = ?").bind(getId()).where("bitrate > 0"));
.where("release_id = ?").bind(getId())
.where("bitrate > 0"));
} }
std::vector<Artist::pointer> Release::getArtists(TrackArtistLinkType linkType) const std::vector<Artist::pointer> Release::getArtists(TrackArtistLinkType linkType) const
@@ -476,8 +454,10 @@ namespace lms::db
"SELECT a FROM artist a" "SELECT a FROM artist a"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id" " INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
" INNER JOIN track t ON t.id = t_a_l.track_id") " INNER JOIN track t ON t.id = t_a_l.track_id")
.where("t.release_id = ?").bind(getId()) .where("t.release_id = ?")
.where("+t_a_l.type = ?").bind(linkType) // adding + since the query planner does not a good job when analyze is not performed .bind(getId())
.where("+t_a_l.type = ?")
.bind(linkType) // adding + since the query planner does not a good job when analyze is not performed
.groupBy("a.id") }; .groupBy("a.id") };
return utils::fetchQueryResults<Artist::pointer>(query); return utils::fetchQueryResults<Artist::pointer>(query);
@@ -499,8 +479,7 @@ namespace lms::db
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id" " INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN release r ON r.id = t.release_id" " INNER JOIN release r ON r.id = t.release_id"
" WHERE r.id = ?)" " WHERE r.id = ?)"
" AND r.id <> ?" " AND r.id <> ?")
)
.bind(getId()) .bind(getId())
.bind(getId()) .bind(getId())
.groupBy("r.id") .groupBy("r.id")
@@ -530,8 +509,7 @@ namespace lms::db
std::size_t Release::getTrackCount() const std::size_t Release::getTrackCount() const
{ {
assert(session()); assert(session());
return utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN release r ON r.id = t.release_id") return utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").bind(getId()));
.where("r.id = ?").bind(getId()));
} }
std::vector<ReleaseType::pointer> Release::getReleaseTypes() const std::vector<ReleaseType::pointer> Release::getReleaseTypes() const
@@ -556,16 +534,14 @@ namespace lms::db
using milli = std::chrono::duration<int, std::milli>; using milli = std::chrono::duration<int, std::milli>;
return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t") return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t").where("t.release_id = ?").bind(getId()));
.where("t.release_id = ?").bind(getId()));
} }
Wt::WDateTime Release::getLastWritten() const Wt::WDateTime Release::getLastWritten() const
{ {
assert(session()); assert(session());
return utils::fetchQuerySingleResult(session()->query<Wt::WDateTime>("SELECT COALESCE(MAX(file_last_write), '1970-01-01T00:00:00') FROM track t") return utils::fetchQuerySingleResult(session()->query<Wt::WDateTime>("SELECT COALESCE(MAX(file_last_write), '1970-01-01T00:00:00') FROM track t").where("t.release_id = ?").bind(getId()));
.where("t.release_id = ?").bind(getId()));
} }
std::vector<std::vector<Cluster::pointer>> Release::getClusterGroups(const std::vector<ClusterTypeId>& clusterTypeIds, std::size_t size) const std::vector<std::vector<Cluster::pointer>> Release::getClusterGroups(const std::vector<ClusterTypeId>& clusterTypeIds, std::size_t size) const
+2 -1
View File
@@ -21,9 +21,10 @@
#include <Wt/Dbo/WtSqlTraits.h> #include <Wt/Dbo/WtSqlTraits.h>
#include "core/String.hpp"
#include "database/MediaLibrary.hpp" #include "database/MediaLibrary.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "core/String.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace lms::db namespace lms::db
+6 -6
View File
@@ -22,7 +22,6 @@
#include "core/Exception.hpp" #include "core/Exception.hpp"
#include "core/ILogger.hpp" #include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp" #include "core/ITraceLogger.hpp"
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/AuthToken.hpp" #include "database/AuthToken.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
@@ -35,22 +34,23 @@
#include "database/StarredRelease.hpp" #include "database/StarredRelease.hpp"
#include "database/StarredTrack.hpp" #include "database/StarredTrack.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "database/TrackBookmark.hpp"
#include "database/TrackArtistLink.hpp" #include "database/TrackArtistLink.hpp"
#include "database/TrackList.hpp" #include "database/TrackBookmark.hpp"
#include "database/TrackFeatures.hpp" #include "database/TrackFeatures.hpp"
#include "database/TrackList.hpp"
#include "database/TransactionChecker.hpp" #include "database/TransactionChecker.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "EnumSetTraits.hpp" #include "EnumSetTraits.hpp"
#include "PathTraits.hpp"
#include "Migration.hpp" #include "Migration.hpp"
#include "PathTraits.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace lms::db namespace lms::db
{ {
WriteTransaction::WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session) WriteTransaction::WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session)
: _lock{ mutex }, : _lock{ mutex }
_transaction{ session } , _transaction{ session }
{ {
#if LMS_CHECK_TRANSACTION_ACCESSES #if LMS_CHECK_TRANSACTION_ACCESSES
TransactionChecker::pushWriteTransaction(_transaction.session()); TransactionChecker::pushWriteTransaction(_transaction.session());
+7 -4
View File
@@ -27,7 +27,8 @@ namespace lms::db
{ {
WhereClause& WhereClause::And(const WhereClause& otherClause) WhereClause& WhereClause::And(const WhereClause& otherClause)
{ {
if (!otherClause._clause.empty()) { if (!otherClause._clause.empty())
{
if (!_clause.empty()) if (!_clause.empty())
_clause += " AND "; _clause += " AND ";
_clause += "(" + otherClause._clause + ")"; _clause += "(" + otherClause._clause + ")";
@@ -43,7 +44,8 @@ namespace lms::db
WhereClause& WhereClause::Or(const WhereClause& otherClause) WhereClause& WhereClause::Or(const WhereClause& otherClause)
{ {
if (!otherClause._clause.empty()) { if (!otherClause._clause.empty())
{
if (!_clause.empty()) if (!_clause.empty())
_clause += " OR "; _clause += " OR ";
_clause += "(" + otherClause._clause + ")"; _clause += "(" + otherClause._clause + ")";
@@ -154,7 +156,8 @@ namespace lms::db
if (!_clause.empty()) if (!_clause.empty())
{ {
oss << "FROM "; oss << "FROM ";
for (auto it = _clause.begin(); it != _clause.end(); ++it) { for (auto it = _clause.begin(); it != _clause.end(); ++it)
{
if (it != _clause.begin()) if (it != _clause.begin())
oss << ","; oss << ",";
@@ -185,4 +188,4 @@ namespace lms::db
return oss.str(); return oss.str();
} }
} } // namespace lms::db
+12 -4
View File
@@ -19,8 +19,8 @@
#pragma once #pragma once
#include <vector>
#include <string> #include <string>
#include <vector>
namespace lms::db namespace lms::db
{ {
@@ -103,9 +103,17 @@ namespace lms::db
{ {
public: public:
SelectStatement& select() { return _selectStatement; } SelectStatement& select() { return _selectStatement; }
SelectStatement& select(const std::string& statement) { _selectStatement = SelectStatement(statement); return _selectStatement; } SelectStatement& select(const std::string& statement)
{
_selectStatement = SelectStatement(statement);
return _selectStatement;
}
FromClause& from() { return _fromClause; } FromClause& from() { return _fromClause; }
FromClause& from(const std::string& clause) { _whereClause = WhereClause(clause); return _fromClause; } FromClause& from(const std::string& clause)
{
_whereClause = WhereClause(clause);
return _fromClause;
}
InnerJoinClause& innerJoin() { return _innerJoinClause; } InnerJoinClause& innerJoin() { return _innerJoinClause; }
WhereClause& where() { return _whereClause; } WhereClause& where() { return _whereClause; }
const WhereClause& where() const { return _whereClause; } const WhereClause& where() const { return _whereClause; }
@@ -121,4 +129,4 @@ namespace lms::db
WhereClause _whereClause; // WHERE clause WhereClause _whereClause; // WHERE clause
GroupByStatement _groupByStatement; // GROUP BY statement GroupByStatement _groupByStatement; // GROUP BY statement
}; };
} } // namespace lms::db
+4 -10
View File
@@ -24,6 +24,7 @@
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "Utils.hpp" #include "Utils.hpp"
@@ -56,24 +57,17 @@ namespace lms::db
StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId) StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredArtist>>("SELECT s_a from starred_artist s_a") return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredArtist>>("SELECT s_a from starred_artist s_a").join("user u ON u.id = s_a.user_id").where("s_a.artist_id = ?").bind(artistId).where("s_a.user_id = ?").bind(userId).where("s_a.backend = u.feedback_backend"));
.join("user u ON u.id = s_a.user_id")
.where("s_a.artist_id = ?").bind(artistId)
.where("s_a.user_id = ?").bind(userId)
.where("s_a.backend = u.feedback_backend"));
} }
StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId, FeedbackBackend backend) StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId, FeedbackBackend backend)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredArtist>() return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredArtist>().where("artist_id = ?").bind(artistId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend));
.where("artist_id = ?").bind(artistId)
.where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend));
} }
void StarredArtist::setDateTime(const Wt::WDateTime& dateTime) void StarredArtist::setDateTime(const Wt::WDateTime& dateTime)
{ {
_dateTime = utils::normalizeDateTime(dateTime); _dateTime = utils::normalizeDateTime(dateTime);
} }
} } // namespace lms::db
+4 -10
View File
@@ -24,6 +24,7 @@
#include "database/Release.hpp" #include "database/Release.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "Utils.hpp" #include "Utils.hpp"
@@ -56,24 +57,17 @@ namespace lms::db
StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId) StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredRelease>>("SELECT s_r from starred_release s_r") return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredRelease>>("SELECT s_r from starred_release s_r").join("user u ON u.id = s_r.user_id").where("s_r.release_id = ?").bind(releaseId).where("s_r.user_id = ?").bind(userId).where("s_r.backend = u.feedback_backend"));
.join("user u ON u.id = s_r.user_id")
.where("s_r.release_id = ?").bind(releaseId)
.where("s_r.user_id = ?").bind(userId)
.where("s_r.backend = u.feedback_backend"));
} }
StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId, FeedbackBackend backend) StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId, FeedbackBackend backend)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredRelease>() return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredRelease>().where("release_id = ?").bind(releaseId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend));
.where("release_id = ?").bind(releaseId)
.where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend));
} }
void StarredRelease::setDateTime(const Wt::WDateTime& dateTime) void StarredRelease::setDateTime(const Wt::WDateTime& dateTime)
{ {
_dateTime = utils::normalizeDateTime(dateTime); _dateTime = utils::normalizeDateTime(dateTime);
} }
} } // namespace lms::db
+6 -15
View File
@@ -21,9 +21,10 @@
#include <Wt/Dbo/WtSqlTraits.h> #include <Wt/Dbo/WtSqlTraits.h>
#include "database/Track.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "Utils.hpp" #include "Utils.hpp"
@@ -56,28 +57,18 @@ namespace lms::db
StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId) StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredTrack>>("SELECT s_t from starred_track s_t") return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredTrack>>("SELECT s_t from starred_track s_t").join("user u ON u.id = s_t.user_id").where("s_t.track_id = ?").bind(trackId).where("s_t.user_id = ?").bind(userId).where("s_t.backend = u.feedback_backend"));
.join("user u ON u.id = s_t.user_id")
.where("s_t.track_id = ?").bind(trackId)
.where("s_t.user_id = ?").bind(userId)
.where("s_t.backend = u.feedback_backend"));
} }
StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend) StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredTrack>() return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredTrack>().where("track_id = ?").bind(trackId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend));
.where("track_id = ?").bind(trackId)
.where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend));
} }
bool StarredTrack::exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend) bool StarredTrack::exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend)
{ {
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT 1 from starred_track") return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT 1 from starred_track").where("track_id = ?").bind(trackId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend));
.where("track_id = ?").bind(trackId)
.where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend));
} }
RangeResults<StarredTrackId> StarredTrack::find(Session& session, const FindParameters& params) RangeResults<StarredTrackId> StarredTrack::find(Session& session, const FindParameters& params)
@@ -100,4 +91,4 @@ namespace lms::db
{ {
_dateTime = utils::normalizeDateTime(dateTime); _dateTime = utils::normalizeDateTime(dateTime);
} }
} } // namespace lms::db
+2 -2
View File
@@ -20,6 +20,7 @@
#pragma once #pragma once
#include <string_view> #include <string_view>
#include <Wt/Dbo/SqlTraits.h> #include <Wt/Dbo/SqlTraits.h>
namespace Wt::Dbo namespace Wt::Dbo
@@ -32,5 +33,4 @@ namespace Wt::Dbo
statement->bind(column, std::string{ str }); statement->bind(column, std::string{ str });
} }
}; };
} } // namespace Wt::Dbo
+27 -37
View File
@@ -21,15 +21,15 @@
#include <Wt/Dbo/WtSqlTraits.h> #include <Wt/Dbo/WtSqlTraits.h>
#include "core/ILogger.hpp"
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "database/MediaLibrary.hpp" #include "database/MediaLibrary.hpp"
#include "database/Release.hpp" #include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/TrackArtistLink.hpp" #include "database/TrackArtistLink.hpp"
#include "database/TrackFeatures.hpp" #include "database/TrackFeatures.hpp"
#include "database/Session.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "core/ILogger.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "PathTraits.hpp" #include "PathTraits.hpp"
@@ -62,16 +62,20 @@ namespace lms::db
{ {
assert(params.feedbackBackend); assert(params.feedbackBackend);
query.join("starred_track s_t ON s_t.track_id = t.id") query.join("starred_track s_t ON s_t.track_id = t.id")
.where("s_t.user_id = ?").bind(params.starringUser) .where("s_t.user_id = ?")
.where("s_t.backend = ?").bind(*params.feedbackBackend) .bind(params.starringUser)
.where("s_t.sync_state <> ?").bind(SyncState::PendingRemove); .where("s_t.backend = ?")
.bind(*params.feedbackBackend)
.where("s_t.sync_state <> ?")
.bind(SyncState::PendingRemove);
} }
if (params.clusters.size() == 1) if (params.clusters.size() == 1)
{ {
// optim // optim
query.join("track_cluster t_c ON t_c.track_id = t.id") query.join("track_cluster t_c ON t_c.track_id = t.id")
.where("t_c.cluster_id = ?").bind(params.clusters.front()); .where("t_c.cluster_id = ?")
.bind(params.clusters.front());
} }
else if (params.clusters.size() > 1) else if (params.clusters.size() > 1)
{ {
@@ -197,7 +201,7 @@ namespace lms::db
return createQuery<ResultType>(session, itemToSelect, params); return createQuery<ResultType>(session, itemToSelect, params);
} }
} } // namespace
Track::pointer Track::create(Session& session) Track::pointer Track::create(Session& session)
{ {
@@ -222,24 +226,19 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<Track>() return utils::fetchQuerySingleResult(session.getDboSession()->find<Track>().where("id = ?").bind(id));
.where("id = ?").bind(id));
} }
void Track::find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function<void(const Track::pointer&)>& func, MediaLibraryId library) void Track::find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function<void(const Track::pointer&)>& func, MediaLibraryId library)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession()->find<Track>() auto query{ session.getDboSession()->find<Track>().orderBy("id").where("id > ?").bind(lastRetrievedTrack).limit(static_cast<int>(count)) };
.orderBy("id")
.where("id > ?").bind(lastRetrievedTrack)
.limit(static_cast<int>(count)) };
if (library.isValid()) if (library.isValid())
query.where("media_library_id = ?").bind(library); query.where("media_library_id = ?").bind(library);
utils::forEachQueryResult(query, [&](const Track::pointer& track) utils::forEachQueryResult(query, [&](const Track::pointer& track) {
{
func(track); func(track);
lastRetrievedTrack = track->getId(); lastRetrievedTrack = track->getId();
}); });
@@ -256,24 +255,21 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>() return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>().where("mbid = ?").bind(mbid.getAsString()));
.where("mbid = ?").bind(mbid.getAsString()));
} }
std::vector<Track::pointer> Track::findByRecordingMBID(Session& session, const core::UUID& mbid) std::vector<Track::pointer> Track::findByRecordingMBID(Session& session, const core::UUID& mbid)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>() return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>().where("recording_mbid = ?").bind(mbid.getAsString()));
.where("recording_mbid = ?").bind(mbid.getAsString()));
} }
RangeResults<TrackId> Track::findIdsTrackMBIDDuplicates(Session& session, std::optional<Range> range) RangeResults<TrackId> Track::findIdsTrackMBIDDuplicates(Session& session, std::optional<Range> range)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession()->query<TrackId>("SELECT track.id FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid <> '' GROUP BY mbid HAVING COUNT (*) > 1)") auto query{ session.getDboSession()->query<TrackId>("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.disc_number,track.track_number,track.mbid") };
.orderBy("track.release_id,track.disc_number,track.track_number,track.mbid") };
return utils::execRangeQuery<TrackId>(query, range); return utils::execRangeQuery<TrackId>(query, range);
} }
@@ -282,9 +278,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession()->query<TrackId>("SELECT t.id FROM track t") auto query{ session.getDboSession()->query<TrackId>("SELECT t.id FROM track t").where("LENGTH(t.recording_mbid) > 0").where("NOT EXISTS (SELECT * FROM track_features t_f WHERE t_f.track_id = t.id)") };
.where("LENGTH(t.recording_mbid) > 0")
.where("NOT EXISTS (SELECT * FROM track_features t_f WHERE t_f.track_id = t.id)") };
return utils::execRangeQuery<TrackId>(query, range); return utils::execRangeQuery<TrackId>(query, range);
} }
@@ -298,10 +292,7 @@ namespace lms::db
{ {
assert(session()); assert(session());
const auto query{ session()->query<ClusterId> const auto query{ session()->query<ClusterId>("SELECT t_c.cluster_id FROM track_cluster t_c").where("t_c.track_id = ?").bind(getId()).groupBy("t_c.cluster_id") };
("SELECT t_c.cluster_id FROM track_cluster t_c")
.where("t_c.track_id = ?").bind(getId())
.groupBy("t_c.cluster_id") };
return utils::fetchQueryResults(query); return utils::fetchQueryResults(query);
} }
@@ -354,8 +345,10 @@ namespace lms::db
auto query{ session.getDboSession()->query<TrackId>( auto query{ session.getDboSession()->query<TrackId>(
"SELECT t.id FROM track t" "SELECT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id" " INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" AND t_c.cluster_id IN (SELECT DISTINCT c.id FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.id WHERE t_c.track_id IN (" + oss.str() + "))" " AND t_c.cluster_id IN (SELECT DISTINCT c.id FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.id WHERE t_c.track_id IN ("
" AND t.id NOT IN (" + oss.str() + ")") + oss.str() + "))"
" AND t.id NOT IN ("
+ oss.str() + ")")
.groupBy("t.id") .groupBy("t.id")
.orderBy("COUNT(*) DESC, RANDOM()") }; .orderBy("COUNT(*) DESC, RANDOM()") };
@@ -412,8 +405,7 @@ namespace lms::db
assert(session()); assert(session());
std::ostringstream oss; std::ostringstream oss;
oss << oss << "SELECT a from artist a"
"SELECT a from artist a"
" INNER JOIN track_artist_link t_a_l ON a.id = t_a_l.artist_id" " INNER JOIN track_artist_link t_a_l ON a.id = t_a_l.artist_id"
" INNER JOIN track t ON t.id = t_a_l.track_id"; " INNER JOIN track t ON t.id = t_a_l.track_id";
@@ -447,8 +439,7 @@ namespace lms::db
assert(session()); assert(session());
std::ostringstream oss; std::ostringstream oss;
oss << oss << "SELECT t_a_l.artist_id FROM track_artist_link t_a_l"
"SELECT t_a_l.artist_id FROM track_artist_link t_a_l"
" INNER JOIN track t ON t.id = t_a_l.track_id"; " INNER JOIN track t ON t.id = t_a_l.track_id";
if (!linkTypes.empty()) if (!linkTypes.empty())
@@ -507,8 +498,7 @@ namespace lms::db
query.bind(bindArg); query.bind(bindArg);
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clusters; std::map<ClusterTypeId, std::vector<Cluster::pointer>> clusters;
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) {
{
if (clusters[cluster->getType()->getId()].size() < size) if (clusters[cluster->getType()->getId()].size() < size)
clusters[cluster->getType()->getId()].push_back(cluster); clusters[cluster->getType()->getId()].push_back(cluster);
}); });
@@ -545,6 +535,6 @@ namespace lms::db
return os; return os;
} }
} } // namespace Debug
} // namespace lms::db } // namespace lms::db
+7 -13
View File
@@ -53,7 +53,7 @@ namespace lms::db
return query; return query;
} }
} } // namespace
TrackArtistLink::TrackArtistLink(ObjectPtr<Track> track, ObjectPtr<Artist> artist, TrackArtistLinkType type, std::string_view subType) TrackArtistLink::TrackArtistLink(ObjectPtr<Track> track, ObjectPtr<Artist> artist, TrackArtistLinkType type, std::string_view subType)
: _type{ type } : _type{ type }
@@ -85,12 +85,9 @@ namespace lms::db
using ResultType = std::tuple<Wt::Dbo::ptr<TrackArtistLink>, Wt::Dbo::ptr<Artist>>; using ResultType = std::tuple<Wt::Dbo::ptr<TrackArtistLink>, Wt::Dbo::ptr<Artist>>;
const auto query{ session.getDboSession()->query<ResultType>("SELECT t_a_l, a FROM track_artist_link t_a_l") const auto query{ session.getDboSession()->query<ResultType>("SELECT t_a_l, a FROM track_artist_link t_a_l").join("artist a ON t_a_l.artist_id = a.id").where("t_a_l.track_id = ?").bind(trackId) };
.join("artist a ON t_a_l.artist_id = a.id")
.where("t_a_l.track_id = ?").bind(trackId) };
utils::forEachQueryResult(query, [&](const ResultType& result) utils::forEachQueryResult(query, [&](const ResultType& result) {
{
func(std::get<Wt::Dbo::ptr<TrackArtistLink>>(result), std::get<Wt::Dbo::ptr<Artist>>(result)); func(std::get<Wt::Dbo::ptr<TrackArtistLink>>(result), std::get<Wt::Dbo::ptr<Artist>>(result));
}); });
} }
@@ -99,8 +96,7 @@ namespace lms::db
{ {
const auto query{ createQuery(session, parameters) }; const auto query{ createQuery(session, parameters) };
utils::forEachQueryResult(query, [&](const TrackArtistLink::pointer& link) utils::forEachQueryResult(query, [&](const TrackArtistLink::pointer& link) {
{
func(link); func(link);
}); });
} }
@@ -109,14 +105,12 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
const auto query{ session.getDboSession()->query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link") const auto query{ session.getDboSession()->query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link").where("artist_id = ?").bind(artistId) };
.where("artist_id = ?").bind(artistId) };
core::EnumSet<TrackArtistLinkType> res; core::EnumSet<TrackArtistLinkType> res;
utils::forEachQueryResult(query, [&](TrackArtistLinkType linkType) utils::forEachQueryResult(query, [&](TrackArtistLinkType linkType) {
{
res.insert(linkType); res.insert(linkType);
}); });
return res; return res;
} }
} } // namespace lms::db
+6 -10
View File
@@ -22,14 +22,15 @@
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace lms::db namespace lms::db
{ {
TrackBookmark::TrackBookmark(ObjectPtr<User> user, ObjectPtr<Track> track) TrackBookmark::TrackBookmark(ObjectPtr<User> user, ObjectPtr<Track> track)
: _user{ getDboPtr(user) }, : _user{ getDboPtr(user) }
_track{ getDboPtr(track) } , _track{ getDboPtr(track) }
{ {
} }
@@ -49,8 +50,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession()->query<TrackBookmarkId>("SELECT id from track_bookmark") auto query{ session.getDboSession()->query<TrackBookmarkId>("SELECT id from track_bookmark").where("user_id = ?").bind(userId) };
.where("user_id = ?").bind(userId) };
return utils::execRangeQuery<TrackBookmarkId>(query, range); return utils::execRangeQuery<TrackBookmarkId>(query, range);
} }
@@ -59,18 +59,14 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>() return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>().where("user_id = ?").bind(userId).where("track_id = ?").bind(trackId));
.where("user_id = ?").bind(userId)
.where("track_id = ?").bind(trackId));
} }
TrackBookmark::pointer TrackBookmark::find(Session& session, TrackBookmarkId id) TrackBookmark::pointer TrackBookmark::find(Session& session, TrackBookmarkId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>() return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>().where("id = ?").bind(id));
.where("id = ?").bind(id));
} }
} // namespace lms::db } // namespace lms::db
+9 -9
View File
@@ -19,20 +19,22 @@
#include "database/TrackFeatures.hpp" #include "database/TrackFeatures.hpp"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include "core/ILogger.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "core/ILogger.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace lms::db { namespace lms::db
{
TrackFeatures::TrackFeatures(ObjectPtr<Track> track, const std::string& jsonEncodedFeatures) TrackFeatures::TrackFeatures(ObjectPtr<Track> track, const std::string& jsonEncodedFeatures)
: _data{ jsonEncodedFeatures }, : _data{ jsonEncodedFeatures }
_track{ getDboPtr(track) } , _track{ getDboPtr(track) }
{ {
} }
@@ -52,16 +54,14 @@ namespace lms::db {
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>() return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>().where("id = ?").bind(id));
.where("id = ?").bind(id));
} }
TrackFeatures::pointer TrackFeatures::find(Session& session, TrackId trackId) TrackFeatures::pointer TrackFeatures::find(Session& session, TrackId trackId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>() return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>().where("track_id = ?").bind(trackId));
.where("track_id = ?").bind(trackId));
} }
RangeResults<TrackFeaturesId> TrackFeatures::find(Session& session, std::optional<Range> range) RangeResults<TrackFeaturesId> TrackFeatures::find(Session& session, std::optional<Range> range)
+14 -28
View File
@@ -21,16 +21,16 @@
#include <cassert> #include <cassert>
#include "core/ILogger.hpp" #include "core/ILogger.hpp"
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "database/Release.hpp" #include "database/Release.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/User.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "SqlQuery.hpp" #include "SqlQuery.hpp"
#include "StringViewTraits.hpp" #include "StringViewTraits.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace lms::db namespace lms::db
@@ -106,7 +106,7 @@ namespace lms::db
return createQuery<ResultType>(session, itemToSelect, params); return createQuery<ResultType>(session, itemToSelect, params);
} }
} } // namespace
TrackList::TrackList(std::string_view name, TrackListType type, bool isPublic, ObjectPtr<User> user) TrackList::TrackList(std::string_view name, TrackListType type, bool isPublic, ObjectPtr<User> user)
: _name{ name } : _name{ name }
@@ -136,10 +136,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
assert(userId.isValid()); assert(userId.isValid());
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackList>() return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackList>().where("name = ?").bind(name).where("type = ?").bind(type).where("user_id = ?").bind(userId));
.where("name = ?").bind(name)
.where("type = ?").bind(type)
.where("user_id = ?").bind(userId));
} }
RangeResults<TrackListId> TrackList::find(Session& session, const FindParameters& params) RangeResults<TrackListId> TrackList::find(Session& session, const FindParameters& params)
@@ -188,9 +185,7 @@ namespace lms::db
{ {
assert(session()); assert(session());
auto query{session()->find<TrackListEntry>() auto query{ session()->find<TrackListEntry>().where("tracklist_id = ?").bind(getId()).orderBy("id") };
.where("tracklist_id = ?").bind(getId())
.orderBy("id") };
return utils::execRangeQuery<TrackListEntry::pointer>(query, range); return utils::execRangeQuery<TrackListEntry::pointer>(query, range);
} }
@@ -199,20 +194,14 @@ namespace lms::db
{ {
assert(session()); assert(session());
return utils::fetchQuerySingleResult(session()->find<TrackListEntry>() return utils::fetchQuerySingleResult(session()->find<TrackListEntry>().where("tracklist_id = ?").bind(getId()).where("track_id = ?").bind(track->getId()).where("date_time = ?").bind(utils::normalizeDateTime(dateTime)));
.where("tracklist_id = ?").bind(getId())
.where("track_id = ?").bind(track->getId())
.where("date_time = ?").bind(utils::normalizeDateTime(dateTime)));
} }
std::vector<Cluster::pointer> TrackList::getClusters() const std::vector<Cluster::pointer> TrackList::getClusters() const
{ {
assert(session()); assert(session());
const auto query{ session()->query<Wt::Dbo::ptr<Cluster>>("SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id") const auto query{ session()->query<Wt::Dbo::ptr<Cluster>>("SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id").where("p.id = ?").bind(getId()).groupBy("c.id").orderBy("COUNT(c.id) DESC") };
.where("p.id = ?").bind(getId())
.groupBy("c.id")
.orderBy("COUNT(c.id) DESC") };
return utils::fetchQueryResults<Cluster::pointer>(query); return utils::fetchQueryResults<Cluster::pointer>(query);
} }
@@ -232,7 +221,8 @@ namespace lms::db
.join("cluster_type c_type ON c.cluster_type_id = c_type.id") .join("cluster_type c_type ON c.cluster_type_id = c_type.id")
.join("tracklist_entry t_l_e ON t_l_e.track_id = t.id") .join("tracklist_entry t_l_e ON t_l_e.track_id = t.id")
.join("tracklist t_l ON t_l.id = t_l_e.tracklist_id") .join("tracklist t_l ON t_l.id = t_l_e.tracklist_id")
.where("t_l.id = ?").bind(getId()); .where("t_l.id = ?")
.bind(getId());
{ {
std::ostringstream oss; std::ostringstream oss;
@@ -253,8 +243,7 @@ namespace lms::db
query.orderBy("COUNT(c.id) DESC"); query.orderBy("COUNT(c.id) DESC");
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType; std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType;
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) {
{
if (clustersByType[cluster->getType()->getId()].size() < size) if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster); clustersByType[cluster->getType()->getId()].push_back(cluster);
}); });
@@ -274,8 +263,7 @@ namespace lms::db
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id" " INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE " " WHERE "
" (t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id WHERE p.id = ?)" " (t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id WHERE p.id = ?)"
" AND t.id NOT IN (SELECT tracklist_t.id FROM track tracklist_t INNER JOIN tracklist_entry t_e ON t_e.track_id = tracklist_t.id WHERE t_e.tracklist_id = ?))" " AND t.id NOT IN (SELECT tracklist_t.id FROM track tracklist_t INNER JOIN tracklist_entry t_e ON t_e.track_id = tracklist_t.id WHERE t_e.tracklist_id = ?))")
)
.bind(getId()) .bind(getId())
.bind(getId()) .bind(getId())
.groupBy("t.id") .groupBy("t.id")
@@ -290,8 +278,7 @@ namespace lms::db
{ {
assert(session()); assert(session());
auto query{ session()->query<TrackId>("SELECT p_e.track_id from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id") auto query{ session()->query<TrackId>("SELECT p_e.track_id from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id").where("p.id = ?").bind(getId()) };
.where("p.id = ?").bind(getId()) };
return utils::fetchQueryResults(query); return utils::fetchQueryResults(query);
} }
@@ -302,8 +289,7 @@ namespace lms::db
using milli = std::chrono::duration<int, std::milli>; using milli = std::chrono::duration<int, std::milli>;
return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN tracklist_entry p_e ON t.id = p_e.track_id") return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN tracklist_entry p_e ON t.id = p_e.track_id").where("p_e.tracklist_id = ?").bind(getId()));
.where("p_e.tracklist_id = ?").bind(getId()));
} }
void TrackList::setLastModifiedDateTime(const Wt::WDateTime& dateTime) void TrackList::setLastModifiedDateTime(const Wt::WDateTime& dateTime)
@@ -22,6 +22,7 @@
static_assert(LMS_CHECK_TRANSACTION_ACCESSES, "File should be excluded from build"); static_assert(LMS_CHECK_TRANSACTION_ACCESSES, "File should be excluded from build");
#include <cassert> #include <cassert>
#include "database/Session.hpp" #include "database/Session.hpp"
namespace lms::db namespace lms::db
@@ -35,7 +36,7 @@ namespace lms::db
}; };
static thread_local std::vector<StackEntry> transactionStack; static thread_local std::vector<StackEntry> transactionStack;
} } // namespace
void TransactionChecker::pushWriteTransaction(Wt::Dbo::Session& session) void TransactionChecker::pushWriteTransaction(Wt::Dbo::Session& session)
{ {
@@ -93,4 +94,4 @@ namespace lms::db
{ {
checkReadTransaction(*session.getDboSession()); checkReadTransaction(*session.getDboSession());
} }
} } // namespace lms::db
+2 -4
View File
@@ -23,8 +23,7 @@
namespace lms::db namespace lms::db
{ {
static const std::set<Bitrate> allowedAudioBitrates static const std::set<Bitrate> allowedAudioBitrates{
{
64000, 64000,
96000, 96000,
128000, 128000,
@@ -47,5 +46,4 @@ namespace lms::db
{ {
return DateRange{ from, to }; return DateRange{ from, to };
} }
} } // namespace lms::db
+3 -3
View File
@@ -19,11 +19,12 @@
#include "database/User.hpp" #include "database/User.hpp"
#include "core/ILogger.hpp"
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Release.hpp" #include "database/Release.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "core/ILogger.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "StringViewTraits.hpp" #include "StringViewTraits.hpp"
#include "Utils.hpp" #include "Utils.hpp"
@@ -87,8 +88,7 @@ namespace lms::db
User::pointer User::find(Session& session, std::string_view name) User::pointer User::find(Session& session, std::string_view name)
{ {
return utils::fetchQuerySingleResult(session.getDboSession()->find<User>() return utils::fetchQuerySingleResult(session.getDboSession()->find<User>().where("login_name = ?").bind(name));
.where("login_name = ?").bind(name));
} }
void User::setSubsonicDefaultTranscodingOutputBitrate(Bitrate bitrate) void User::setSubsonicDefaultTranscodingOutputBitrate(Bitrate bitrate)

Some files were not shown because too many files have changed in this diff Show More