1
0
mirror of https://github.com/clangen/musikcube.git synced 2025-02-19 15:40:50 +00:00

Fixed broken TrackMetadataQuery, and also implemented generic metadata

queries in CategoryTrackListQuery. CategoryListQuery still unsupported
-- that's gonna be the hard one.
This commit is contained in:
casey langen 2018-01-01 00:28:07 -08:00
parent 14c823fb63
commit d5ff695eed
3 changed files with 130 additions and 66 deletions

@ -39,7 +39,6 @@
#include <core/library/track/LibraryTrack.h>
#include <core/library/LocalLibraryConstants.h>
#include <core/db/Statement.h>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string.hpp>
@ -58,18 +57,15 @@ using namespace musik::core::library::constants;
using namespace boost::algorithm;
static std::map<std::string, std::string> FIELD_TO_FOREIGN_KEY = {
std::make_pair(Track::ALBUM, Track::ALBUM_ID),
std::make_pair(Track::ARTIST, Track::ARTIST_ID),
std::make_pair(Track::GENRE, Track::GENRE_ID),
std::make_pair(Track::ALBUM_ARTIST, Track::ALBUM_ARTIST_ID),
std::make_pair(Playlists::TABLE_NAME, Playlists::TABLE_NAME)
{ Track::ALBUM, Track::ALBUM_ID },
{ Track::ARTIST, Track::ARTIST_ID },
{ Track::GENRE, Track::GENRE_ID },
{ Track::ALBUM_ARTIST, Track::ALBUM_ARTIST_ID },
{ Playlists::TABLE_NAME, Playlists::TABLE_NAME }
};
CategoryTrackListQuery::CategoryTrackListQuery(
ILibraryPtr library,
const std::string& column,
int64_t id,
const std::string& filter)
ILibraryPtr library, const std::string& column, int64_t id, const std::string& filter)
{
this->library = library;
this->id = id;
@ -81,11 +77,14 @@ CategoryTrackListQuery::CategoryTrackListQuery(
this->filter = "%" + trim_copy(to_lower_copy(filter)) + "%";
}
if (FIELD_TO_FOREIGN_KEY.find(column) == FIELD_TO_FOREIGN_KEY.end()) {
throw std::runtime_error("invalid input column specified");
if (FIELD_TO_FOREIGN_KEY.find(column) != FIELD_TO_FOREIGN_KEY.end()) {
this->type = (column == Playlists::TABLE_NAME) ? Playlist : Regular;
this->column = FIELD_TO_FOREIGN_KEY[column]; /* optimized query */
}
else {
this->type = Extended;
this->column = column; /* generalized query */
}
this->column = FIELD_TO_FOREIGN_KEY[column];
}
CategoryTrackListQuery::~CategoryTrackListQuery() {
@ -111,64 +110,121 @@ size_t CategoryTrackListQuery::GetQueryHash() {
return this->hash;
}
bool CategoryTrackListQuery::OnRun(Connection& db) {
if (result) {
result.reset(new musik::core::TrackList(this->library));
headers.reset(new std::set<size_t>());
void CategoryTrackListQuery::PlaylistQuery(musik::core::db::Connection &db) {
/* playlists are a special case. we already have a query for this, so
delegate to that. */
GetPlaylistQuery query(this->library, this->id);
query.Run(db);
this->result = query.GetResult();
}
void CategoryTrackListQuery::RegularQuery(musik::core::db::Connection &db) {
/* these are the most common queries in the app, and are more optimized
than extended metadata queries. */
std::string query =
"SELECT DISTINCT t.id, al.name "
"FROM tracks t, albums al, artists ar, genres gn "
"WHERE t.visible=1 AND t.%s=? AND t.album_id=al.id AND t.visual_genre_id=gn.id AND t.visual_artist_id=ar.id ";
if (this->filter.size()) {
query += " AND (t.title LIKE ? OR al.name LIKE ? OR ar.name LIKE ? OR gn.name LIKE ?) ";
}
if (this->column == Playlists::TABLE_NAME) {
/* playlists are a special case. we already have a query for this, so
delegate to that. */
query += "ORDER BY al.name, disc, track, ar.name %s";
query = boost::str(boost::format(query) % this->column % this->GetLimitAndOffset());
GetPlaylistQuery query(this->library, this->id);
query.Run(db);
this->result = query.GetResult();
Statement trackQuery(query.c_str(), db);
if (this->filter.size()) {
trackQuery.BindInt64(0, this->id);
trackQuery.BindText(1, this->filter);
trackQuery.BindText(2, this->filter);
trackQuery.BindText(3, this->filter);
trackQuery.BindText(4, this->filter);
}
else {
/* regular old category query... */
trackQuery.BindInt64(0, this->id);
}
std::string lastAlbum;
size_t index = 0;
this->ProcessResult(trackQuery);
}
void CategoryTrackListQuery::ExtendedQuery(musik::core::db::Connection &db) {
int64_t keyId = 0;
{
Statement keyQuery("SELECT DISTINCT id FROM meta_keys WHERE LOWER(name)=LOWER(?)", db);
keyQuery.BindText(0, this->column);
if (keyQuery.Step() == db::Row) {
keyId = keyQuery.ColumnInt64(0);
}
}
if (keyId > 0) {
/* the core library allows for storage of arbitrary metadata in the form
of key/value pairs linked to tracks. they are slower and require additional
joins and subqueries, but are fully supported here. */
std::string query =
"SELECT DISTINCT t.id, al.name "
"FROM tracks t, albums al, artists ar, genres gn "
"WHERE t.visible=1 AND t.%s=? AND t.album_id=al.id AND t.visual_genre_id=gn.id AND t.visual_artist_id=ar.id ";
"FROM tracks t, albums al, artists ar, genres gn, track_meta tm, meta_keys mk, meta_values mv "
"WHERE t.visible=1 "
" AND t.album_id=al.id AND t.visual_genre_id=gn.id AND t.visual_artist_id=ar.id "
" AND t.id=tm.track_id AND tm.meta_value_id=mv.id AND mv.meta_key_id=mk.id "
" AND mk.id=? AND mv.id=? ";
if (this->filter.size()) {
query += " AND (t.title LIKE ? OR al.name LIKE ? OR ar.name LIKE ? OR gn.name LIKE ?) ";
}
query += "ORDER BY al.name, disc, track, ar.name %s";
query = boost::str(boost::format(query) % this->column % this->GetLimitAndOffset());
query = boost::str(boost::format(query) % this->GetLimitAndOffset());
Statement trackQuery(query.c_str(), db);
int bindOffset = 0;
trackQuery.BindInt64(bindOffset++, keyId);
trackQuery.BindInt64(bindOffset++, this->id);
if (this->filter.size()) {
trackQuery.BindInt64(0, this->id);
trackQuery.BindText(1, this->filter);
trackQuery.BindText(2, this->filter);
trackQuery.BindText(3, this->filter);
trackQuery.BindText(4, this->filter);
}
else {
trackQuery.BindInt64(0, this->id);
trackQuery.BindText(bindOffset++, this->filter);
trackQuery.BindText(bindOffset++, this->filter);
trackQuery.BindText(bindOffset++, this->filter);
trackQuery.BindText(bindOffset++, this->filter);
}
while (trackQuery.Step() == Row) {
int64_t id = trackQuery.ColumnInt64(0);
std::string album = trackQuery.ColumnText(1);
if (album != lastAlbum) {
headers->insert(index);
lastAlbum = album;
}
result->Add(id);
++index;
}
this->ProcessResult(trackQuery);
}
}
void CategoryTrackListQuery::ProcessResult(musik::core::db::Statement& trackQuery) {
std::string lastAlbum;
size_t index = 0;
while (trackQuery.Step() == Row) {
int64_t id = trackQuery.ColumnInt64(0);
std::string album = trackQuery.ColumnText(1);
if (album != lastAlbum) {
headers->insert(index);
lastAlbum = album;
}
result->Add(id);
++index;
}
}
bool CategoryTrackListQuery::OnRun(Connection& db) {
if (result) {
result.reset(new musik::core::TrackList(this->library));
headers.reset(new std::set<size_t>());
}
switch (this->type) {
case Playlist: this->PlaylistQuery(db); break;
case Regular: this->RegularQuery(db); break;
case Extended: this->ExtendedQuery(db); break;
}
return true;
}

@ -37,6 +37,7 @@
#include <core/db/Connection.h>
#include <core/library/track/Track.h>
#include <core/library/query/local/LocalQueryBase.h>
#include <core/db/Statement.h>
#include "TrackListQueryBase.h"
@ -62,10 +63,18 @@ namespace musik { namespace core { namespace db { namespace local {
virtual bool OnRun(musik::core::db::Connection &db);
private:
enum Type { Playlist, Regular, Extended };
void PlaylistQuery(musik::core::db::Connection &db);
void RegularQuery(musik::core::db::Connection &db);
void ExtendedQuery(musik::core::db::Connection &db);
void ProcessResult(musik::core::db::Statement& stmt);
musik::core::ILibraryPtr library;
Result result;
Headers headers;
std::string column;
Type type;
int64_t id;
size_t hash;
std::string filter;

@ -104,21 +104,20 @@ bool TrackMetadataQuery::OnRun(Connection& db) {
result->SetValue(constants::Track::BPM, trackQuery.ColumnText(2));
result->SetValue(constants::Track::DURATION, trackQuery.ColumnText(3));
result->SetValue(constants::Track::FILESIZE, trackQuery.ColumnText(4));
result->SetValue(constants::Track::YEAR, trackQuery.ColumnText(5));
result->SetValue(constants::Track::TITLE, trackQuery.ColumnText(6));
result->SetValue(constants::Track::FILENAME, trackQuery.ColumnText(7));
result->SetValue(constants::Track::THUMBNAIL_ID, trackQuery.ColumnText(8));
result->SetValue(constants::Track::ALBUM, trackQuery.ColumnText(9));
result->SetValue(constants::Track::ALBUM_ARTIST, trackQuery.ColumnText(10));
result->SetValue(constants::Track::GENRE, trackQuery.ColumnText(11));
result->SetValue(constants::Track::ARTIST, trackQuery.ColumnText(12));
result->SetValue(constants::Track::FILETIME, trackQuery.ColumnText(13));
result->SetValue(constants::Track::GENRE_ID, trackQuery.ColumnText(14));
result->SetValue(constants::Track::ARTIST_ID, trackQuery.ColumnText(15));
result->SetValue(constants::Track::ALBUM_ARTIST_ID, trackQuery.ColumnText(16));
result->SetValue(constants::Track::ALBUM_ID, trackQuery.ColumnText(17));
result->SetValue(constants::Track::SOURCE_ID, trackQuery.ColumnText(18));
result->SetValue(constants::Track::EXTERNAL_ID, trackQuery.ColumnText(19));
result->SetValue(constants::Track::TITLE, trackQuery.ColumnText(5));
result->SetValue(constants::Track::FILENAME, trackQuery.ColumnText(6));
result->SetValue(constants::Track::THUMBNAIL_ID, trackQuery.ColumnText(7));
result->SetValue(constants::Track::ALBUM, trackQuery.ColumnText(8));
result->SetValue(constants::Track::ALBUM_ARTIST, trackQuery.ColumnText(9));
result->SetValue(constants::Track::GENRE, trackQuery.ColumnText(10));
result->SetValue(constants::Track::ARTIST, trackQuery.ColumnText(11));
result->SetValue(constants::Track::FILETIME, trackQuery.ColumnText(12));
result->SetValue(constants::Track::GENRE_ID, trackQuery.ColumnText(13));
result->SetValue(constants::Track::ARTIST_ID, trackQuery.ColumnText(14));
result->SetValue(constants::Track::ALBUM_ARTIST_ID, trackQuery.ColumnText(15));
result->SetValue(constants::Track::ALBUM_ID, trackQuery.ColumnText(16));
result->SetValue(constants::Track::SOURCE_ID, trackQuery.ColumnText(17));
result->SetValue(constants::Track::EXTERNAL_ID, trackQuery.ColumnText(18));
}
else {
result->SetValue(constants::Track::EXTERNAL_ID, trackQuery.ColumnText(0));