mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-29 19:20:28 +00:00
Updated CategoryTrackListQuery to support predicate lists, just like
CategoryListQuery.
This commit is contained in:
parent
273212bd0d
commit
6c354f513b
@ -34,13 +34,9 @@
|
||||
|
||||
#include "pch.hpp"
|
||||
#include "CategoryListQuery.h"
|
||||
|
||||
#include <core/library/LocalLibraryConstants.h>
|
||||
#include <core/db/Statement.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
|
||||
using musik::core::db::Statement;
|
||||
using musik::core::db::Row;
|
||||
|
||||
@ -50,15 +46,6 @@ using namespace musik::core::db::local;
|
||||
|
||||
#define RESET_RESULT(x) x.reset(new std::vector<std::shared_ptr<Result>>);
|
||||
|
||||
#if 1
|
||||
#ifdef WIN32
|
||||
#define DUMP(x) OutputDebugStringA(x.c_str()); OutputDebugStringA("\n");
|
||||
#else
|
||||
#include <iostream>
|
||||
#define DUMP(x) std::cout << x << "\n";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static const std::string UNFILTERED_PLAYLISTS_QUERY =
|
||||
"SELECT DISTINCT id, name "
|
||||
"FROM playlists "
|
||||
@ -93,14 +80,6 @@ class ValueList : public musik::core::sdk::IValueList {
|
||||
CategoryListQuery::ResultList results;
|
||||
};
|
||||
|
||||
static void replaceAll(std::string& input, const std::string& find, const std::string& replace) {
|
||||
size_t pos = input.find(find);
|
||||
while (pos != std::string::npos) {
|
||||
input.replace(pos, find.size(), replace);
|
||||
pos = input.find(find, pos + replace.size());
|
||||
}
|
||||
}
|
||||
|
||||
CategoryListQuery::CategoryListQuery(
|
||||
const std::string& trackField, const std::string& filter)
|
||||
: CategoryListQuery(trackField, category::PredicateList(), filter) {
|
||||
@ -128,7 +107,6 @@ CategoryListQuery::CategoryListQuery(
|
||||
this->filter = "%" + wild + "%";
|
||||
}
|
||||
|
||||
|
||||
category::SplitPredicates(predicates, this->regular, this->extended);
|
||||
|
||||
auto end = category::REGULAR_PROPERTY_MAP.end();
|
||||
@ -184,6 +162,8 @@ void CategoryListQuery::QueryPlaylist(musik::core::db::Connection& db) {
|
||||
void CategoryListQuery::QueryRegular(musik::core::db::Connection &db) {
|
||||
category::ArgumentList args;
|
||||
|
||||
/* order of operations with args is important! otherwise bind params
|
||||
will be out of order! */
|
||||
auto prop = category::REGULAR_PROPERTY_MAP[this->trackField];
|
||||
std::string query = category::REGULAR_PROPERTY_QUERY;
|
||||
std::string extended = InnerJoinExtended(this->extended, args);
|
||||
@ -192,15 +172,15 @@ void CategoryListQuery::QueryRegular(musik::core::db::Connection &db) {
|
||||
|
||||
if (this->filter.size()) {
|
||||
regularFilter = category::REGULAR_FILTER;
|
||||
replaceAll(regularFilter, "{{table}}", prop.first);
|
||||
category::ReplaceAll(regularFilter, "{{table}}", prop.first);
|
||||
args.push_back(category::StringArgument(this->filter));
|
||||
}
|
||||
|
||||
replaceAll(query, "{{table}}", prop.first);
|
||||
replaceAll(query, "{{fk_id}}", prop.second);
|
||||
replaceAll(query, "{{extended_predicates}}", extended);
|
||||
replaceAll(query, "{{regular_predicates}}", regular);
|
||||
replaceAll(query, "{{regular_filter}}", regularFilter);
|
||||
category::ReplaceAll(query, "{{table}}", prop.first);
|
||||
category::ReplaceAll(query, "{{fk_id}}", prop.second);
|
||||
category::ReplaceAll(query, "{{extended_predicates}}", extended);
|
||||
category::ReplaceAll(query, "{{regular_predicates}}", regular);
|
||||
category::ReplaceAll(query, "{{regular_filter}}", regularFilter);
|
||||
|
||||
Statement stmt(query.c_str(), db);
|
||||
Apply(stmt, args);
|
||||
@ -210,6 +190,8 @@ void CategoryListQuery::QueryRegular(musik::core::db::Connection &db) {
|
||||
void CategoryListQuery::QueryExtended(musik::core::db::Connection &db) {
|
||||
category::ArgumentList args;
|
||||
|
||||
/* order of operations with args is important! otherwise bind params
|
||||
will be out of order! */
|
||||
std::string query = category::EXTENDED_PROPERTY_QUERY;
|
||||
std::string regular = category::JoinRegular(this->regular, args, " AND ");
|
||||
std::string extended = category::InnerJoinExtended(this->extended, args);
|
||||
@ -220,14 +202,12 @@ void CategoryListQuery::QueryExtended(musik::core::db::Connection &db) {
|
||||
args.push_back(category::StringArgument(this->filter));
|
||||
}
|
||||
|
||||
replaceAll(query, "{{regular_predicates}}", regular);
|
||||
replaceAll(query, "{{extended_predicates}}", extended);
|
||||
replaceAll(query, "{{extended_filter}}", extendedFilter);
|
||||
category::ReplaceAll(query, "{{regular_predicates}}", regular);
|
||||
category::ReplaceAll(query, "{{extended_predicates}}", extended);
|
||||
category::ReplaceAll(query, "{{extended_filter}}", extendedFilter);
|
||||
|
||||
args.push_back(category::StringArgument(this->trackField));
|
||||
|
||||
DUMP(query);
|
||||
|
||||
Statement stmt(query.c_str(), db);
|
||||
Apply(stmt, args);
|
||||
ProcessResult(stmt);
|
||||
|
@ -43,8 +43,6 @@
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
using musik::core::db::Statement;
|
||||
using musik::core::db::Row;
|
||||
using musik::core::TrackPtr;
|
||||
@ -56,34 +54,44 @@ using namespace musik::core::db::local;
|
||||
using namespace musik::core::library::constants;
|
||||
using namespace boost::algorithm;
|
||||
|
||||
static std::map<std::string, std::string> FIELD_TO_FOREIGN_KEY = {
|
||||
{ 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(
|
||||
musik::core::ILibraryPtr library,
|
||||
const std::string& column,
|
||||
int64_t id,
|
||||
const std::string& filter)
|
||||
: CategoryTrackListQuery(library, { column, id }, filter)
|
||||
{
|
||||
}
|
||||
|
||||
CategoryTrackListQuery::CategoryTrackListQuery(
|
||||
ILibraryPtr library, const std::string& column, int64_t id, const std::string& filter)
|
||||
ILibraryPtr library,
|
||||
const category::Predicate predicate,
|
||||
const std::string& filter)
|
||||
: CategoryTrackListQuery(library, category::PredicateList { predicate }, filter)
|
||||
{
|
||||
}
|
||||
|
||||
CategoryTrackListQuery::CategoryTrackListQuery(
|
||||
ILibraryPtr library,
|
||||
const category::PredicateList predicates,
|
||||
const std::string& filter)
|
||||
{
|
||||
this->library = library;
|
||||
this->id = id;
|
||||
this->result.reset(new musik::core::TrackList(library));
|
||||
this->headers.reset(new std::set<size_t>());
|
||||
this->hash = 0;
|
||||
this->hash = category::Hash(predicates);
|
||||
|
||||
category::SplitPredicates(predicates, this->regular, this->extended);
|
||||
|
||||
if (filter.size()) {
|
||||
this->filter = "%" + trim_copy(to_lower_copy(filter)) + "%";
|
||||
}
|
||||
|
||||
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 */
|
||||
if (predicates.size() == 1 && predicates[0].first == Playlists::TABLE_NAME) {
|
||||
this->type = Playlist;
|
||||
}
|
||||
else {
|
||||
this->type = Extended;
|
||||
this->column = column; /* generalized query */
|
||||
this->type = Regular;
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,100 +108,44 @@ CategoryTrackListQuery::Headers CategoryTrackListQuery::GetHeaders() {
|
||||
}
|
||||
|
||||
size_t CategoryTrackListQuery::GetQueryHash() {
|
||||
if (this->hash == 0) {
|
||||
std::string parts = boost::str(
|
||||
boost::format("%s-%s") % this->column % this->id);
|
||||
|
||||
this->hash = std::hash<std::string>()(parts);
|
||||
}
|
||||
|
||||
return this->hash;
|
||||
}
|
||||
|
||||
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);
|
||||
GetPlaylistQuery query(this->library, this->extended[0].second);
|
||||
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 ";
|
||||
category::ArgumentList args;
|
||||
|
||||
/* order of operations with args is important! otherwise bind params
|
||||
will be out of order! */
|
||||
std::string query = category::CATEGORY_TRACKLIST_QUERY;
|
||||
std::string extended = InnerJoinExtended(this->extended, args);
|
||||
std::string regular = JoinRegular(this->regular, args, " AND ");
|
||||
std::string trackFilter;
|
||||
std::string limitAndOffset = this->GetLimitAndOffset();
|
||||
|
||||
if (this->filter.size()) {
|
||||
query += " AND (t.title LIKE ? OR al.name LIKE ? OR ar.name LIKE ? OR gn.name LIKE ?) ";
|
||||
trackFilter = " AND " + category::CATEGORY_TRACKLIST_FILTER;
|
||||
args.push_back(category::StringArgument(this->filter));
|
||||
args.push_back(category::StringArgument(this->filter));
|
||||
args.push_back(category::StringArgument(this->filter));
|
||||
args.push_back(category::StringArgument(this->filter));
|
||||
}
|
||||
|
||||
query += "ORDER BY al.name, disc, track, ar.name %s";
|
||||
query = boost::str(boost::format(query) % this->column % this->GetLimitAndOffset());
|
||||
category::ReplaceAll(query, "{{extended_predicates}}", extended);
|
||||
category::ReplaceAll(query, "{{regular_predicates}}", regular);
|
||||
category::ReplaceAll(query, "{{tracklist_filter}}", trackFilter);
|
||||
category::ReplaceAll(query, "{{limit_and_offset}}", limitAndOffset);
|
||||
|
||||
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 {
|
||||
trackQuery.BindInt64(0, this->id);
|
||||
}
|
||||
|
||||
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, 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->GetLimitAndOffset());
|
||||
|
||||
Statement trackQuery(query.c_str(), db);
|
||||
|
||||
int bindOffset = 0;
|
||||
trackQuery.BindInt64(bindOffset++, keyId);
|
||||
trackQuery.BindInt64(bindOffset++, this->id);
|
||||
|
||||
if (this->filter.size()) {
|
||||
trackQuery.BindText(bindOffset++, this->filter);
|
||||
trackQuery.BindText(bindOffset++, this->filter);
|
||||
trackQuery.BindText(bindOffset++, this->filter);
|
||||
trackQuery.BindText(bindOffset++, this->filter);
|
||||
}
|
||||
|
||||
this->ProcessResult(trackQuery);
|
||||
}
|
||||
Statement stmt(query.c_str(), db);
|
||||
category::Apply(stmt, args);
|
||||
this->ProcessResult(stmt);
|
||||
}
|
||||
|
||||
void CategoryTrackListQuery::ProcessResult(musik::core::db::Statement& trackQuery) {
|
||||
@ -223,7 +175,6 @@ bool CategoryTrackListQuery::OnRun(Connection& db) {
|
||||
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/library/query/local/util/CategoryQueryUtil.h>
|
||||
#include <core/db/Statement.h>
|
||||
|
||||
#include "TrackListQueryBase.h"
|
||||
@ -51,6 +52,16 @@ namespace musik { namespace core { namespace db { namespace local {
|
||||
int64_t id,
|
||||
const std::string& filter = "");
|
||||
|
||||
CategoryTrackListQuery(
|
||||
musik::core::ILibraryPtr library,
|
||||
const category::Predicate predicate,
|
||||
const std::string& filter = "");
|
||||
|
||||
CategoryTrackListQuery(
|
||||
musik::core::ILibraryPtr library,
|
||||
const category::PredicateList predicates,
|
||||
const std::string& filter = "");
|
||||
|
||||
virtual ~CategoryTrackListQuery();
|
||||
|
||||
virtual std::string Name() { return "CategoryTrackListQuery"; }
|
||||
@ -63,19 +74,17 @@ namespace musik { namespace core { namespace db { namespace local {
|
||||
virtual bool OnRun(musik::core::db::Connection &db);
|
||||
|
||||
private:
|
||||
enum Type { Playlist, Regular, Extended };
|
||||
enum Type { Playlist, Regular };
|
||||
|
||||
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;
|
||||
category::PredicateList regular, extended;
|
||||
size_t hash;
|
||||
std::string filter;
|
||||
};
|
||||
|
@ -115,7 +115,7 @@ std::shared_ptr<SavePlaylistQuery> SavePlaylistQuery::Replace(
|
||||
|
||||
std::shared_ptr<SavePlaylistQuery> SavePlaylistQuery::Rename(
|
||||
musik::core::ILibraryPtr library,
|
||||
const int64_t playlistId,
|
||||
const int64_t playlistId,
|
||||
const std::string& playlistName)
|
||||
{
|
||||
return std::shared_ptr<SavePlaylistQuery>(
|
||||
|
@ -45,14 +45,6 @@ using namespace musik::core::db;
|
||||
using namespace musik::core::library::constants;
|
||||
using namespace musik::core::db::local;
|
||||
|
||||
static void replaceAll(std::string& input, const std::string& find, const std::string& replace) {
|
||||
size_t pos = input.find(find);
|
||||
while (pos != std::string::npos) {
|
||||
input.replace(pos, find.size(), replace);
|
||||
pos = input.find(find, pos + replace.size());
|
||||
}
|
||||
}
|
||||
|
||||
namespace musik { namespace core { namespace db { namespace local { namespace category {
|
||||
|
||||
struct Id : public Argument {
|
||||
@ -75,6 +67,18 @@ namespace musik { namespace core { namespace db { namespace local { namespace ca
|
||||
return std::make_shared<String>(str);
|
||||
}
|
||||
|
||||
void ReplaceAll(
|
||||
std::string& input,
|
||||
const std::string& find,
|
||||
const std::string& replace)
|
||||
{
|
||||
size_t pos = input.find(find);
|
||||
while (pos != std::string::npos) {
|
||||
input.replace(pos, find.size(), replace);
|
||||
pos = input.find(find, pos + replace.size());
|
||||
}
|
||||
}
|
||||
|
||||
PropertyType GetPropertyType(const std::string& property) {
|
||||
auto found = REGULAR_PROPERTY_MAP.find(property);
|
||||
auto end = REGULAR_PROPERTY_MAP.end();
|
||||
@ -84,6 +88,14 @@ namespace musik { namespace core { namespace db { namespace local { namespace ca
|
||||
: category::PropertyType::Regular;
|
||||
}
|
||||
|
||||
size_t Hash(const PredicateList& input) {
|
||||
std::string key = "";
|
||||
for (auto p : input) {
|
||||
key += p.first + std::to_string(p.second);
|
||||
}
|
||||
return std::hash<std::string>()(key);
|
||||
}
|
||||
|
||||
void SplitPredicates(
|
||||
const PredicateList& input,
|
||||
PredicateList& regular,
|
||||
@ -113,7 +125,7 @@ namespace musik { namespace core { namespace db { namespace local { namespace ca
|
||||
auto p = pred[i];
|
||||
auto str = REGULAR_PREDICATE;
|
||||
auto map = REGULAR_PROPERTY_MAP[p.first];
|
||||
replaceAll(str, "{{fk_id}}", map.second);
|
||||
ReplaceAll(str, "{{fk_id}}", map.second);
|
||||
result += str;
|
||||
args.push_back(std::make_shared<Id>(p.second));
|
||||
}
|
||||
@ -133,8 +145,8 @@ namespace musik { namespace core { namespace db { namespace local { namespace ca
|
||||
std::string joined = JoinExtended(pred, args);
|
||||
if (joined.size()) {
|
||||
result = EXTENDED_INNER_JOIN;
|
||||
replaceAll(result, "{{extended_predicates}}", joined);
|
||||
replaceAll(result, "{{extended_predicate_count}}", std::to_string(pred.size()));
|
||||
ReplaceAll(result, "{{extended_predicates}}", joined);
|
||||
ReplaceAll(result, "{{extended_predicate_count}}", std::to_string(pred.size()));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -102,8 +102,8 @@ namespace musik { namespace core { namespace db { namespace local {
|
||||
// HAVING COUNT(track_id) = 2
|
||||
// ) AS md ON tracks.id = md.track_id
|
||||
// WHERE
|
||||
// albums.id = tracks.album_id AND
|
||||
// tracks.visible = 1;
|
||||
// albums.id = tracks.album_id AND
|
||||
// tracks.visible = 1;
|
||||
|
||||
static const std::string REGULAR_PROPERTY_QUERY =
|
||||
"SELECT DISTINCT {{table}}.id, {{table}}.name "
|
||||
@ -130,12 +130,13 @@ namespace musik { namespace core { namespace db { namespace local {
|
||||
// SELECT id AS track_id
|
||||
// FROM extended_metadata
|
||||
// WHERE
|
||||
// (key = "composer" AND value = "J. Cantrell")
|
||||
// (key = "composer" AND value = "J. Cantrell") OR
|
||||
// ...
|
||||
// GROUP BY track_id
|
||||
// HAVING COUNT(track_id) = 1
|
||||
// ) AS md ON extended_metadata.id = md.track_id
|
||||
// WHERE
|
||||
// extended_metadata.key = "year";
|
||||
// extended_metadata.key = "year";
|
||||
|
||||
static const std::string EXTENDED_PROPERTY_QUERY =
|
||||
"SELECT DISTINCT meta_value_id, value "
|
||||
@ -150,6 +151,38 @@ namespace musik { namespace core { namespace db { namespace local {
|
||||
"{{extended_filter}} "
|
||||
"ORDER BY extended_metadata.value ASC";
|
||||
|
||||
/* used to select all tracks that match a specified set of predicates. both
|
||||
regular and extended predicates are supported. in essense: */
|
||||
|
||||
// SELECT DISTINCT tracks.*
|
||||
// FROM tracks
|
||||
// INNER JOIN(
|
||||
// SELECT id AS track_id
|
||||
// FROM extended_metadata
|
||||
// WHERE
|
||||
// (key = "year" AND value = "1995") OR
|
||||
// (key = "composer" AND value = "J. Cantrell")
|
||||
// GROUP BY track_id
|
||||
// HAVING COUNT(track_id) = 2
|
||||
// ) AS md ON tracks.id = md.track_id;
|
||||
|
||||
static const std::string CATEGORY_TRACKLIST_FILTER =
|
||||
" AND (tracks.title LIKE ? OR al.name LIKE ? OR ar.name LIKE ? OR gn.name LIKE ?) ";
|
||||
|
||||
static const std::string CATEGORY_TRACKLIST_QUERY =
|
||||
"SELECT DISTINCT tracks.id, al.name "
|
||||
"FROM tracks, albums al, artists ar, genres gn "
|
||||
"{{extended_predicates}} "
|
||||
"WHERE "
|
||||
" tracks.visible=1 AND "
|
||||
" tracks.album_id=al.id AND "
|
||||
" tracks.visual_genre_id=gn.id AND "
|
||||
" tracks.visual_artist_id=ar.id "
|
||||
" {{regular_predicates}} "
|
||||
" {{tracklist_filter}} "
|
||||
"ORDER BY al.name, disc, track, ar.name "
|
||||
"{{limit_and_offset}} ";
|
||||
|
||||
using Predicate = std::pair<std::string, int64_t>;
|
||||
using PredicateList = std::vector<Predicate>;
|
||||
struct Argument { virtual void Bind(Statement& stmt, int pos) const = 0; };
|
||||
@ -160,6 +193,13 @@ namespace musik { namespace core { namespace db { namespace local {
|
||||
extern std::shared_ptr<Argument> IdArgument(int64_t);
|
||||
extern std::shared_ptr<Argument> StringArgument(const std::string);
|
||||
|
||||
extern size_t Hash(const PredicateList& input);
|
||||
|
||||
extern void ReplaceAll(
|
||||
std::string& input,
|
||||
const std::string& find,
|
||||
const std::string& replace);
|
||||
|
||||
extern void SplitPredicates(
|
||||
const PredicateList& input,
|
||||
PredicateList& regular,
|
||||
|
@ -211,11 +211,9 @@ void BrowseLayout::RequeryTrackList(ListWindow *view) {
|
||||
if (view == this->categoryList.get()) {
|
||||
int64_t selectedId = this->categoryList->GetSelectedId();
|
||||
if (selectedId != -1) {
|
||||
auto column = this->categoryList->GetFieldName();
|
||||
this->trackList->Requery(std::shared_ptr<TrackListQueryBase>(
|
||||
new CategoryTrackListQuery(
|
||||
this->library,
|
||||
this->categoryList->GetFieldName(),
|
||||
selectedId)));
|
||||
new CategoryTrackListQuery(this->library, column, selectedId)));
|
||||
}
|
||||
else {
|
||||
this->trackList->Clear();
|
||||
|
Loading…
x
Reference in New Issue
Block a user