Fixed output bug for values, added some optims
This commit is contained in:
@@ -32,11 +32,11 @@ namespace Database
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
Wt::Dbo::Query<ClusterId> createQuery(Session& session, const Cluster::FindParameters& params)
|
Wt::Dbo::Query<Cluster::ClusterFindResult> createQuery(Session& session, const Cluster::FindParameters& params)
|
||||||
{
|
{
|
||||||
session.checkSharedLocked();
|
session.checkSharedLocked();
|
||||||
|
|
||||||
auto query{ session.getDboSession().query<ClusterId>("SELECT DISTINCT c.id FROM cluster c") };
|
auto query{ session.getDboSession().query<Cluster::ClusterFindResult>("SELECT DISTINCT c.id,c.name FROM cluster c") };
|
||||||
|
|
||||||
if (params.track.isValid() || params.release.isValid())
|
if (params.track.isValid() || params.release.isValid())
|
||||||
{
|
{
|
||||||
@@ -74,7 +74,7 @@ namespace Database
|
|||||||
return session.getDboSession().query<int>("SELECT COUNT(*) FROM cluster");
|
return session.getDboSession().query<int>("SELECT COUNT(*) FROM cluster");
|
||||||
}
|
}
|
||||||
|
|
||||||
RangeResults<ClusterId> Cluster::find(Session& session, const FindParameters& params)
|
RangeResults<Cluster::ClusterFindResult> Cluster::find(Session& session, const FindParameters& params)
|
||||||
{
|
{
|
||||||
session.checkSharedLocked();
|
session.checkSharedLocked();
|
||||||
auto query{ createQuery(session, params) };
|
auto query{ createQuery(session, params) };
|
||||||
|
|||||||
@@ -672,7 +672,7 @@ CREATE TABLE IF NOT EXISTS "track_backup" (
|
|||||||
|
|
||||||
if (version == LMS_DATABASE_VERSION)
|
if (version == LMS_DATABASE_VERSION)
|
||||||
{
|
{
|
||||||
LMS_LOG(DB, DEBUG) << "Lms database version " << LMS_DATABASE_VERSION << ": up to date!";
|
LMS_LOG(DB, INFO) << "Lms database version " << LMS_DATABASE_VERSION << ": up to date!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (version > LMS_DATABASE_VERSION)
|
else if (version > LMS_DATABASE_VERSION)
|
||||||
@@ -683,13 +683,15 @@ CREATE TABLE IF NOT EXISTS "track_backup" (
|
|||||||
if (version < migrationFunctions.begin()->first)
|
if (version < migrationFunctions.begin()->first)
|
||||||
throw LmsException{ outdatedMsg };
|
throw LmsException{ outdatedMsg };
|
||||||
|
|
||||||
LMS_LOG(DB, INFO) << "Migrating database from version " << version << "...";
|
LMS_LOG(DB, INFO) << "Migrating database from version " << version << " to " << version + 1 << "...";
|
||||||
|
|
||||||
auto itMigrationFunc{ migrationFunctions.find(version) };
|
auto itMigrationFunc{ migrationFunctions.find(version) };
|
||||||
assert(itMigrationFunc != std::cend(migrationFunctions));
|
assert(itMigrationFunc != std::cend(migrationFunctions));
|
||||||
itMigrationFunc->second(session);
|
itMigrationFunc->second(session);
|
||||||
|
|
||||||
VersionInfo::get(session).modify()->setVersion(++version);
|
VersionInfo::get(session).modify()->setVersion(++version);
|
||||||
|
|
||||||
|
LMS_LOG(DB, INFO) << "Migration complete to version " << version;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <Wt/Dbo/Dbo.h>
|
#include <Wt/Dbo/Dbo.h>
|
||||||
@@ -58,10 +59,12 @@ namespace Database {
|
|||||||
Cluster() = default;
|
Cluster() = default;
|
||||||
|
|
||||||
// Find utility
|
// Find utility
|
||||||
static std::size_t getCount(Session& session);
|
// As clusters only have a name, this is an optim to directly get the cluster names
|
||||||
static RangeResults<ClusterId> find(Session& session, const FindParameters& range);
|
using ClusterFindResult = std::tuple<ClusterId, std::string>;
|
||||||
static pointer find(Session& session, ClusterId id);
|
static std::size_t getCount(Session& session);
|
||||||
static RangeResults<ClusterId> findOrphans(Session& session, Range range);
|
static RangeResults<ClusterFindResult> find(Session& session, const FindParameters& range);
|
||||||
|
static pointer find(Session& session, ClusterId id);
|
||||||
|
static RangeResults<ClusterId> findOrphans(Session& session, Range range);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
const std::string& getName() const { return _name; }
|
const std::string& getName() const { return _name; }
|
||||||
|
|||||||
@@ -48,13 +48,17 @@ TEST_F(DatabaseFixture, Cluster)
|
|||||||
EXPECT_EQ(Cluster::getCount(session), 1);
|
EXPECT_EQ(Cluster::getCount(session), 1);
|
||||||
EXPECT_EQ(cluster->getType()->getId(), clusterType.getId());
|
EXPECT_EQ(cluster->getType()->getId(), clusterType.getId());
|
||||||
|
|
||||||
auto clusters{ Cluster::find(session, Cluster::FindParameters {}) };
|
{
|
||||||
ASSERT_EQ(clusters.results.size(), 1);
|
const auto clusters{ Cluster::find(session, Cluster::FindParameters {}) };
|
||||||
EXPECT_EQ(clusters.results.front(), cluster.getId());
|
ASSERT_EQ(clusters.results.size(), 1);
|
||||||
|
EXPECT_EQ(std::get<ClusterId>(clusters.results.front()), cluster.getId());
|
||||||
|
}
|
||||||
|
|
||||||
clusters = Cluster::findOrphans(session, Range{});
|
{
|
||||||
ASSERT_EQ(clusters.results.size(), 1);
|
const auto clusters{ Cluster::findOrphans(session, Range{}) };
|
||||||
EXPECT_EQ(clusters.results.front(), cluster.getId());
|
ASSERT_EQ(clusters.results.size(), 1);
|
||||||
|
EXPECT_EQ(clusters.results.front(), cluster.getId());
|
||||||
|
}
|
||||||
|
|
||||||
auto clusterTypes{ ClusterType::find(session, Range {}) };
|
auto clusterTypes{ ClusterType::find(session, Range {}) };
|
||||||
ASSERT_EQ(clusterTypes.results.size(), 1);
|
ASSERT_EQ(clusterTypes.results.size(), 1);
|
||||||
@@ -114,7 +118,7 @@ TEST_F(DatabaseFixture, Cluster_singleTrack)
|
|||||||
auto transaction{ session.createSharedTransaction() };
|
auto transaction{ session.createSharedTransaction() };
|
||||||
auto clusters{ Cluster::find(session, Cluster::FindParameters {}.setTrack(track.getId())) };
|
auto clusters{ Cluster::find(session, Cluster::FindParameters {}.setTrack(track.getId())) };
|
||||||
ASSERT_EQ(clusters.results.size(), 1);
|
ASSERT_EQ(clusters.results.size(), 1);
|
||||||
EXPECT_EQ(clusters.results.front(), cluster1.getId());
|
EXPECT_EQ(std::get<ClusterId>(clusters.results.front()), cluster1.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -317,9 +321,9 @@ TEST_F(DatabaseFixture, Cluster_singleTrackSingleReleaseSingleCluster)
|
|||||||
{
|
{
|
||||||
auto transaction{ session.createSharedTransaction() };
|
auto transaction{ session.createSharedTransaction() };
|
||||||
|
|
||||||
auto clusters{ Cluster::find(session, Cluster::FindParameters{}.setRelease(release.getId())) };
|
const auto clusters{ Cluster::find(session, Cluster::FindParameters{}.setRelease(release.getId())) };
|
||||||
ASSERT_EQ(clusters.results.size(), 1);
|
ASSERT_EQ(clusters.results.size(), 1);
|
||||||
EXPECT_EQ(clusters.results.front(), cluster.getId());
|
EXPECT_EQ(std::get<ClusterId>(clusters.results.front()), cluster.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1106,5 +1110,3 @@ TEST_F(DatabaseFixture, MultipleTracksMultipleReleasesMultiClusters)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ namespace API::Subsonic
|
|||||||
_attributes[key] = std::string{ value };
|
_attributes[key] = std::string{ value };
|
||||||
}
|
}
|
||||||
|
|
||||||
void Response::Node::addChild(Key key, Node node)
|
void Response::Node::addChild(Key key, Node&& node)
|
||||||
{
|
{
|
||||||
assert(!_value);
|
assert(!_value);
|
||||||
assert(_children.find(key) == std::cend(_children));
|
assert(_children.find(key) == std::cend(_children));
|
||||||
@@ -72,7 +72,7 @@ namespace API::Subsonic
|
|||||||
_childrenArrays.emplace(key, std::vector<Node>{});
|
_childrenArrays.emplace(key, std::vector<Node>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Response::Node::addArrayChild(Key key, Node node)
|
void Response::Node::addArrayChild(Key key, Node&& node)
|
||||||
{
|
{
|
||||||
assert(!_value);
|
assert(!_value);
|
||||||
assert(_children.find(key) == std::cend(_children));
|
assert(_children.find(key) == std::cend(_children));
|
||||||
@@ -155,7 +155,7 @@ namespace API::Subsonic
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Response::addNode(Node::Key key, Node node)
|
void Response::addNode(Node::Key key, Node&& node)
|
||||||
{
|
{
|
||||||
return _root._children["subsonic-response"].addChild(key, std::move(node));
|
return _root._children["subsonic-response"].addChild(key, std::move(node));
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ namespace API::Subsonic
|
|||||||
if (!first)
|
if (!first)
|
||||||
os << ',';
|
os << ',';
|
||||||
|
|
||||||
os << "value:";
|
os << "\"value\":";
|
||||||
serializeValue(os, *node._value);
|
serializeValue(os, *node._value);
|
||||||
|
|
||||||
first = false;
|
first = false;
|
||||||
|
|||||||
@@ -225,9 +225,9 @@ namespace API::Subsonic
|
|||||||
Node& createChild(Key key);
|
Node& createChild(Key key);
|
||||||
Node& createArrayChild(Key key);
|
Node& createArrayChild(Key key);
|
||||||
|
|
||||||
void addChild(Key key, Node node);
|
void addChild(Key key, Node&& node);
|
||||||
void createEmptyArrayChild(Key key);
|
void createEmptyArrayChild(Key key);
|
||||||
void addArrayChild(Key key, Node node);
|
void addArrayChild(Key key, Node&& node);
|
||||||
void createEmptyArrayValue(Key key);
|
void createEmptyArrayValue(Key key);
|
||||||
void addArrayValue(Key key, std::string_view value);
|
void addArrayValue(Key key, std::string_view value);
|
||||||
void addArrayValue(Key key, long long value);
|
void addArrayValue(Key key, long long value);
|
||||||
@@ -255,7 +255,7 @@ namespace API::Subsonic
|
|||||||
Response(Response&&) = default;
|
Response(Response&&) = default;
|
||||||
Response& operator=(Response&&) = default;
|
Response& operator=(Response&&) = default;
|
||||||
|
|
||||||
void addNode(Node::Key key, Node node);
|
void addNode(Node::Key key, Node&& node);
|
||||||
Node& createNode(Node::Key key);
|
Node& createNode(Node::Key key);
|
||||||
Node& createArrayNode(Node::Key key);
|
Node& createArrayNode(Node::Key key);
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace API::Subsonic
|
|||||||
for (const TrackListEntry::pointer& entry : entries)
|
for (const TrackListEntry::pointer& entry : entries)
|
||||||
playlistNode.addArrayChild("entry", createSongNode(entry->getTrack(), context.dbSession, user));
|
playlistNode.addArrayChild("entry", createSongNode(entry->getTrack(), context.dbSession, user));
|
||||||
|
|
||||||
response.addNode("playlist", playlistNode);
|
response.addNode("playlist", std::move(playlistNode));
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ namespace API::Subsonic
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (const Wt::WDateTime dateTime{ Service<Scrobbling::IScrobblingService>::get()->getStarredDateTime(user->getId(), release->getId()) }; dateTime.isValid())
|
if (const Wt::WDateTime dateTime{ Service<Scrobbling::IScrobblingService>::get()->getStarredDateTime(user->getId(), release->getId()) }; dateTime.isValid())
|
||||||
albumNode.setAttribute("starred", StringUtils::toISO8601String(dateTime)); // TODO report correct date/time
|
albumNode.setAttribute("starred", StringUtils::toISO8601String(dateTime));
|
||||||
|
|
||||||
// OpenSubsonic specific fields (must always be set)
|
// OpenSubsonic specific fields (must always be set)
|
||||||
if (!id3)
|
if (!id3)
|
||||||
@@ -160,33 +160,23 @@ namespace API::Subsonic
|
|||||||
params.setRelease(release->getId());
|
params.setRelease(release->getId());
|
||||||
params.setClusterType(clusterType->getId());
|
params.setClusterType(clusterType->getId());
|
||||||
|
|
||||||
for (const ClusterId clusterId : Cluster::find(dbSession, params).results)
|
for (const auto& cluster : Cluster::find(dbSession, params).results)
|
||||||
{
|
albumNode.addArrayValue(field, std::get<std::string>(cluster));
|
||||||
Cluster::pointer cluster{ Cluster::find(dbSession, clusterId) };
|
|
||||||
if (cluster)
|
|
||||||
albumNode.addArrayValue(field, cluster->getName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} };
|
} };
|
||||||
|
|
||||||
addClusters("moods", "MOOD");
|
addClusters("moods", "MOOD");
|
||||||
|
|
||||||
// Genres
|
// Genres
|
||||||
|
albumNode.createEmptyArrayChild("genres");
|
||||||
|
if (genreClusterType)
|
||||||
{
|
{
|
||||||
albumNode.createEmptyArrayChild("genres");
|
Cluster::FindParameters params;
|
||||||
if (genreClusterType)
|
params.setRelease(release->getId());
|
||||||
{
|
params.setClusterType(genreClusterType->getId());
|
||||||
Cluster::FindParameters params;
|
|
||||||
params.setRelease(release->getId());
|
|
||||||
params.setClusterType(genreClusterType->getId());
|
|
||||||
|
|
||||||
for (const ClusterId clusterId : Cluster::find(dbSession, params).results)
|
for (const auto& cluster : Cluster::find(dbSession, params).results)
|
||||||
{
|
albumNode.addArrayChild("genres", createItemGenreNode(std::get<std::string>(cluster)));
|
||||||
Cluster::pointer cluster{ Cluster::find(dbSession, clusterId) };
|
|
||||||
if (cluster)
|
|
||||||
albumNode.addArrayChild("genres", createItemGenreNode(cluster));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
albumNode.createEmptyArrayChild("artists");
|
albumNode.createEmptyArrayChild("artists");
|
||||||
|
|||||||
@@ -23,11 +23,11 @@
|
|||||||
|
|
||||||
namespace API::Subsonic
|
namespace API::Subsonic
|
||||||
{
|
{
|
||||||
Response::Node createItemGenreNode(const Database::Cluster::pointer& cluster)
|
Response::Node createItemGenreNode(std::string_view name)
|
||||||
{
|
{
|
||||||
Response::Node genreNode;
|
Response::Node genreNode;
|
||||||
|
|
||||||
genreNode.setAttribute("name", cluster->getName());
|
genreNode.setAttribute("name", name);
|
||||||
|
|
||||||
return genreNode;
|
return genreNode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "services/database/Object.hpp"
|
#include <string_view>
|
||||||
#include "SubsonicResponse.hpp"
|
#include "SubsonicResponse.hpp"
|
||||||
|
|
||||||
namespace Database
|
namespace Database
|
||||||
@@ -29,5 +29,5 @@ namespace Database
|
|||||||
|
|
||||||
namespace API::Subsonic
|
namespace API::Subsonic
|
||||||
{
|
{
|
||||||
Response::Node createItemGenreNode(const Database::ObjectPtr<Database::Cluster>& cluster);
|
Response::Node createItemGenreNode(std::string_view name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -221,34 +221,23 @@ namespace API::Subsonic
|
|||||||
params.setTrack(track->getId());
|
params.setTrack(track->getId());
|
||||||
params.setClusterType(clusterType->getId());
|
params.setClusterType(clusterType->getId());
|
||||||
|
|
||||||
for (const ClusterId clusterId : Cluster::find(dbSession, params).results)
|
for (const auto& cluster : Cluster::find(dbSession, params).results)
|
||||||
{
|
trackResponse.addArrayValue(field, std::get<std::string>(cluster));
|
||||||
Cluster::pointer cluster {Cluster::find(dbSession, clusterId)};
|
|
||||||
if (cluster)
|
|
||||||
trackResponse.addArrayValue(field, cluster->getName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} };
|
} };
|
||||||
|
|
||||||
addClusters("moods", "MOOD");
|
addClusters("moods", "MOOD");
|
||||||
|
|
||||||
// Genres
|
// Genres
|
||||||
|
trackResponse.createEmptyArrayChild("genres");
|
||||||
|
if (genreClusterType)
|
||||||
{
|
{
|
||||||
trackResponse.createEmptyArrayChild("genres");
|
Cluster::FindParameters params;
|
||||||
|
params.setTrack(track->getId());
|
||||||
|
params.setClusterType(genreClusterType->getId());
|
||||||
|
|
||||||
if (genreClusterType)
|
for (const auto& cluster : Cluster::find(dbSession, params).results)
|
||||||
{
|
trackResponse.addArrayChild("genres", createItemGenreNode(std::get<std::string>(cluster)));
|
||||||
Cluster::FindParameters params;
|
|
||||||
params.setTrack(track->getId());
|
|
||||||
params.setClusterType(genreClusterType->getId());
|
|
||||||
|
|
||||||
for (const ClusterId clusterId : Cluster::find(dbSession, params).results)
|
|
||||||
{
|
|
||||||
Cluster::pointer cluster{ Cluster::find(dbSession, clusterId) };
|
|
||||||
if (cluster)
|
|
||||||
trackResponse.addArrayChild("genres", createItemGenreNode(cluster));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trackResponse.addChild("replayGain", createReplayGainNode(track));
|
trackResponse.addChild("replayGain", createReplayGainNode(track));
|
||||||
|
|||||||
Reference in New Issue
Block a user