mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-11 09:40:26 +00:00
Added regex support to CategoryListQuery and SearchTrackListQuery, but
they're not wired up yet.
This commit is contained in:
parent
ba9b98794f
commit
d4a1fba4b6
@ -305,6 +305,7 @@ ITrackList* LocalMetadataProxy::QueryTracks(const char* query, int limit, int of
|
|||||||
std::shared_ptr<SearchTrackListQuery> search(
|
std::shared_ptr<SearchTrackListQuery> search(
|
||||||
new SearchTrackListQuery(
|
new SearchTrackListQuery(
|
||||||
this->library,
|
this->library,
|
||||||
|
SearchTrackListQuery::MatchType::Substring,
|
||||||
std::string(query ? query : ""),
|
std::string(query ? query : ""),
|
||||||
TrackSortType::Album));
|
TrackSortType::Album));
|
||||||
|
|
||||||
@ -456,6 +457,7 @@ IValueList* LocalMetadataProxy::QueryCategoryWithPredicate(
|
|||||||
|
|
||||||
std::shared_ptr<CategoryListQuery> search(
|
std::shared_ptr<CategoryListQuery> search(
|
||||||
new CategoryListQuery(
|
new CategoryListQuery(
|
||||||
|
CategoryListQuery::MatchType::Substring,
|
||||||
type,
|
type,
|
||||||
{ field, predicateId },
|
{ field, predicateId },
|
||||||
std::string(filter ? filter : "")));
|
std::string(filter ? filter : "")));
|
||||||
@ -480,7 +482,10 @@ IValueList* LocalMetadataProxy::QueryCategoryWithPredicates(
|
|||||||
auto predicateList = toPredicateList(predicates, predicateCount);
|
auto predicateList = toPredicateList(predicates, predicateCount);
|
||||||
|
|
||||||
auto query = std::make_shared<CategoryListQuery>(
|
auto query = std::make_shared<CategoryListQuery>(
|
||||||
type, predicateList, std::string(filter ? filter : ""));
|
CategoryListQuery::MatchType::Substring,
|
||||||
|
type,
|
||||||
|
predicateList,
|
||||||
|
std::string(filter ? filter : ""));
|
||||||
|
|
||||||
this->library->EnqueueAndWait(query);
|
this->library->EnqueueAndWait(query);
|
||||||
|
|
||||||
|
@ -50,6 +50,11 @@ namespace musik { namespace core { namespace library { namespace query {
|
|||||||
public sigslot::has_slots<>
|
public sigslot::has_slots<>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum class MatchType : int {
|
||||||
|
Substring = 1,
|
||||||
|
Regex = 2
|
||||||
|
};
|
||||||
|
|
||||||
QueryBase()
|
QueryBase()
|
||||||
: status(IQuery::Idle)
|
: status(IQuery::Idle)
|
||||||
, options(0)
|
, options(0)
|
||||||
|
@ -56,35 +56,44 @@ static const std::string kUnfilteredPlaylistsQuery =
|
|||||||
static const std::string kFilteredPlaylistsQuery =
|
static const std::string kFilteredPlaylistsQuery =
|
||||||
"SELECT DISTINCT id, name "
|
"SELECT DISTINCT id, name "
|
||||||
"FROM playlists"
|
"FROM playlists"
|
||||||
"WHERE LOWER(name) LIKE LOWER(?) "
|
"WHERE LOWER(name) {{match_type}} ? "
|
||||||
"ORDER BY name;";
|
"ORDER BY name;";
|
||||||
|
|
||||||
const std::string CategoryListQuery::kQueryName = "CategoryListQuery";
|
const std::string CategoryListQuery::kQueryName = "CategoryListQuery";
|
||||||
|
|
||||||
|
static std::string getMatchType(CategoryListQuery::MatchType matchType) {
|
||||||
|
return matchType == CategoryListQuery::MatchType::Regex ? "REGEXP" : "LIKE";
|
||||||
|
}
|
||||||
|
|
||||||
CategoryListQuery::CategoryListQuery() {
|
CategoryListQuery::CategoryListQuery() {
|
||||||
}
|
}
|
||||||
|
|
||||||
CategoryListQuery::CategoryListQuery(
|
CategoryListQuery::CategoryListQuery(
|
||||||
const std::string& trackField, const std::string& filter)
|
MatchType matchType,
|
||||||
: CategoryListQuery(trackField, category::PredicateList(), filter) {
|
const std::string& trackField,
|
||||||
|
const std::string& filter)
|
||||||
|
: CategoryListQuery(matchType, trackField, category::PredicateList(), filter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CategoryListQuery::CategoryListQuery(
|
CategoryListQuery::CategoryListQuery(
|
||||||
|
MatchType matchType,
|
||||||
const std::string& trackField,
|
const std::string& trackField,
|
||||||
const category::Predicate predicate,
|
const category::Predicate predicate,
|
||||||
const std::string& filter)
|
const std::string& filter)
|
||||||
: CategoryListQuery(trackField, category::PredicateList{ predicate }, filter) {
|
: CategoryListQuery(matchType, trackField, category::PredicateList{ predicate }, filter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CategoryListQuery::CategoryListQuery(
|
CategoryListQuery::CategoryListQuery(
|
||||||
|
MatchType matchType,
|
||||||
const std::string& trackField,
|
const std::string& trackField,
|
||||||
const category::PredicateList predicates,
|
const category::PredicateList predicates,
|
||||||
const std::string& filter)
|
const std::string& filter)
|
||||||
: trackField(trackField)
|
: matchType(MatchType::Regex)
|
||||||
|
, trackField(trackField)
|
||||||
, filter(filter) {
|
, filter(filter) {
|
||||||
result.reset(new SdkValueList());
|
result.reset(new SdkValueList());
|
||||||
|
|
||||||
if (this->filter.size()) {
|
if (this->filter.size() && this->matchType == MatchType::Substring) {
|
||||||
/* transform "FilteR" => "%filter%" */
|
/* transform "FilteR" => "%filter%" */
|
||||||
std::string wild = this->filter;
|
std::string wild = this->filter;
|
||||||
std::transform(wild.begin(), wild.end(), wild.begin(), tolower);
|
std::transform(wild.begin(), wild.end(), wild.begin(), tolower);
|
||||||
@ -134,6 +143,8 @@ void CategoryListQuery::QueryPlaylist(musik::core::db::Connection& db) {
|
|||||||
? kFilteredPlaylistsQuery
|
? kFilteredPlaylistsQuery
|
||||||
: kUnfilteredPlaylistsQuery;
|
: kUnfilteredPlaylistsQuery;
|
||||||
|
|
||||||
|
category::ReplaceAll(query, "{{match_type}}", getMatchType(matchType));
|
||||||
|
|
||||||
Statement stmt(query.c_str() , db);
|
Statement stmt(query.c_str() , db);
|
||||||
|
|
||||||
if (filtered) {
|
if (filtered) {
|
||||||
@ -157,6 +168,7 @@ void CategoryListQuery::QueryRegular(musik::core::db::Connection &db) {
|
|||||||
if (this->filter.size()) {
|
if (this->filter.size()) {
|
||||||
regularFilter = category::REGULAR_FILTER;
|
regularFilter = category::REGULAR_FILTER;
|
||||||
category::ReplaceAll(regularFilter, "{{table}}", prop.first);
|
category::ReplaceAll(regularFilter, "{{table}}", prop.first);
|
||||||
|
category::ReplaceAll(regularFilter, "{{match_type}}", getMatchType(matchType));
|
||||||
args.push_back(category::StringArgument(this->filter));
|
args.push_back(category::StringArgument(this->filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,6 +196,7 @@ void CategoryListQuery::QueryExtended(musik::core::db::Connection &db) {
|
|||||||
if (this->filter.size()) {
|
if (this->filter.size()) {
|
||||||
extendedFilter = category::EXTENDED_FILTER;
|
extendedFilter = category::EXTENDED_FILTER;
|
||||||
args.push_back(category::StringArgument(this->filter));
|
args.push_back(category::StringArgument(this->filter));
|
||||||
|
category::ReplaceAll(extendedFilter, "{{match_type}}", getMatchType(matchType));
|
||||||
}
|
}
|
||||||
|
|
||||||
category::ReplaceAll(query, "{{regular_predicates}}", regular);
|
category::ReplaceAll(query, "{{regular_predicates}}", regular);
|
||||||
@ -242,6 +255,7 @@ std::string CategoryListQuery::SerializeQuery() {
|
|||||||
query["options"] = {
|
query["options"] = {
|
||||||
{ "trackField", this->trackField },
|
{ "trackField", this->trackField },
|
||||||
{ "filter", this->filter },
|
{ "filter", this->filter },
|
||||||
|
{ "matchType", this->matchType },
|
||||||
{ "outputType", this->outputType },
|
{ "outputType", this->outputType },
|
||||||
{ "regularPredicateList", PredicateListToJson(this->regular) },
|
{ "regularPredicateList", PredicateListToJson(this->regular) },
|
||||||
{ "extendedPredicateList", PredicateListToJson(this->extended) }
|
{ "extendedPredicateList", PredicateListToJson(this->extended) }
|
||||||
@ -269,6 +283,7 @@ std::shared_ptr<CategoryListQuery> CategoryListQuery::DeserializeQuery(const std
|
|||||||
std::shared_ptr<CategoryListQuery> result(new CategoryListQuery());
|
std::shared_ptr<CategoryListQuery> result(new CategoryListQuery());
|
||||||
result->trackField = options.value("trackField", "");
|
result->trackField = options.value("trackField", "");
|
||||||
result->filter = options.value("filter", "");
|
result->filter = options.value("filter", "");
|
||||||
|
result->matchType = options.value("matchType", MatchType::Substring);
|
||||||
result->outputType = (OutputType)options.value("outputType", OutputType::Regular);
|
result->outputType = (OutputType)options.value("outputType", OutputType::Regular);
|
||||||
PredicateListFromJson(options["regularPredicateList"], result->regular);
|
PredicateListFromJson(options["regularPredicateList"], result->regular);
|
||||||
PredicateListFromJson(options["extendedPredicateList"], result->extended);
|
PredicateListFromJson(options["extendedPredicateList"], result->extended);
|
||||||
|
@ -52,15 +52,18 @@ namespace musik { namespace core { namespace library { namespace query {
|
|||||||
using Result = SdkValueList::Shared;
|
using Result = SdkValueList::Shared;
|
||||||
|
|
||||||
CategoryListQuery(
|
CategoryListQuery(
|
||||||
|
MatchType matchType,
|
||||||
const std::string& trackField,
|
const std::string& trackField,
|
||||||
const std::string& filter = "");
|
const std::string& filter = "");
|
||||||
|
|
||||||
CategoryListQuery(
|
CategoryListQuery(
|
||||||
|
MatchType matchType,
|
||||||
const std::string& trackField,
|
const std::string& trackField,
|
||||||
const category::Predicate predicate,
|
const category::Predicate predicate,
|
||||||
const std::string& filter = "");
|
const std::string& filter = "");
|
||||||
|
|
||||||
CategoryListQuery(
|
CategoryListQuery(
|
||||||
|
MatchType matchType,
|
||||||
const std::string& trackField,
|
const std::string& trackField,
|
||||||
const category::PredicateList predicate,
|
const category::PredicateList predicate,
|
||||||
const std::string& filter = "");
|
const std::string& filter = "");
|
||||||
@ -100,6 +103,7 @@ namespace musik { namespace core { namespace library { namespace query {
|
|||||||
|
|
||||||
std::string trackField;
|
std::string trackField;
|
||||||
std::string filter;
|
std::string filter;
|
||||||
|
MatchType matchType;
|
||||||
OutputType outputType;
|
OutputType outputType;
|
||||||
category::PredicateList regular, extended;
|
category::PredicateList regular, extended;
|
||||||
Result result;
|
Result result;
|
||||||
|
@ -61,9 +61,13 @@ using namespace boost::algorithm;
|
|||||||
const std::string SearchTrackListQuery::kQueryName = "SearchTrackListQuery";
|
const std::string SearchTrackListQuery::kQueryName = "SearchTrackListQuery";
|
||||||
|
|
||||||
SearchTrackListQuery::SearchTrackListQuery(
|
SearchTrackListQuery::SearchTrackListQuery(
|
||||||
ILibraryPtr library, const std::string& filter, TrackSortType sort)
|
ILibraryPtr library,
|
||||||
|
MatchType matchType,
|
||||||
|
const std::string& filter,
|
||||||
|
TrackSortType sort)
|
||||||
{
|
{
|
||||||
this->library = library;
|
this->library = library;
|
||||||
|
this->matchType = matchType;
|
||||||
this->sortType = sort;
|
this->sortType = sort;
|
||||||
this->filter = filter;
|
this->filter = filter;
|
||||||
|
|
||||||
@ -105,11 +109,10 @@ bool SearchTrackListQuery::OnRun(Connection& db) {
|
|||||||
headers.reset(new std::set<size_t>());
|
headers.reset(new std::set<size_t>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool useRegex = (matchType == MatchType::Regex);
|
||||||
bool hasFilter = (this->filter.size() > 0);
|
bool hasFilter = (this->filter.size() > 0);
|
||||||
|
|
||||||
std::string lastAlbum;
|
std::string lastAlbum;
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
|
|
||||||
std::string query;
|
std::string query;
|
||||||
|
|
||||||
if (hasFilter) {
|
if (hasFilter) {
|
||||||
@ -119,9 +122,11 @@ bool SearchTrackListQuery::OnRun(Connection& db) {
|
|||||||
"WHERE "
|
"WHERE "
|
||||||
" tracks.visible=1 AND "
|
" tracks.visible=1 AND "
|
||||||
+ this->orderByPredicate +
|
+ this->orderByPredicate +
|
||||||
"(tracks.title LIKE ? OR al.name LIKE ? OR ar.name LIKE ? OR gn.name LIKE ?) "
|
"(tracks.title {{match_type}} ? OR al.name {{match_type}} ? OR ar.name {{match_type}} ? OR gn.name {{match_type}} ?) "
|
||||||
" AND tracks.album_id=al.id AND tracks.visual_genre_id=gn.id AND tracks.visual_artist_id=ar.id "
|
" AND tracks.album_id=al.id AND tracks.visual_genre_id=gn.id AND tracks.visual_artist_id=ar.id "
|
||||||
"ORDER BY " + this->orderBy + " ";
|
"ORDER BY " + this->orderBy + " ";
|
||||||
|
|
||||||
|
ReplaceAll(query, "{{match_type}}", useRegex ? "REGEXP" : "LIKE");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
query =
|
query =
|
||||||
@ -139,11 +144,13 @@ bool SearchTrackListQuery::OnRun(Connection& db) {
|
|||||||
Statement trackQuery(query.c_str(), db);
|
Statement trackQuery(query.c_str(), db);
|
||||||
|
|
||||||
if (hasFilter) {
|
if (hasFilter) {
|
||||||
std::string filterWithWildcard = "%" + trim_copy(to_lower_copy(filter)) + "%";
|
std::string patternToMatch = useRegex
|
||||||
trackQuery.BindText(0, filterWithWildcard);
|
? filter : "%" + trim_copy(to_lower_copy(filter)) + "%";
|
||||||
trackQuery.BindText(1, filterWithWildcard);
|
|
||||||
trackQuery.BindText(2, filterWithWildcard);
|
trackQuery.BindText(0, patternToMatch);
|
||||||
trackQuery.BindText(3, filterWithWildcard);
|
trackQuery.BindText(1, patternToMatch);
|
||||||
|
trackQuery.BindText(2, patternToMatch);
|
||||||
|
trackQuery.BindText(3, patternToMatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (trackQuery.Step() == Row) {
|
while (trackQuery.Step() == Row) {
|
||||||
@ -173,7 +180,8 @@ std::string SearchTrackListQuery::SerializeQuery() {
|
|||||||
{ "name", kQueryName },
|
{ "name", kQueryName },
|
||||||
{ "options", {
|
{ "options", {
|
||||||
{ "filter", filter },
|
{ "filter", filter },
|
||||||
{ "sortType", sortType}
|
{ "matchType", matchType },
|
||||||
|
{ "sortType", sortType }
|
||||||
}}
|
}}
|
||||||
};
|
};
|
||||||
return FinalizeSerializedQueryWithLimitAndOffset(output);
|
return FinalizeSerializedQueryWithLimitAndOffset(output);
|
||||||
@ -194,6 +202,7 @@ std::shared_ptr<SearchTrackListQuery> SearchTrackListQuery::DeserializeQuery(mus
|
|||||||
auto options = nlohmann::json::parse(data)["options"];
|
auto options = nlohmann::json::parse(data)["options"];
|
||||||
auto result = std::make_shared<SearchTrackListQuery>(
|
auto result = std::make_shared<SearchTrackListQuery>(
|
||||||
library,
|
library,
|
||||||
|
options.value("matchType", MatchType::Substring),
|
||||||
options["filter"].get<std::string>(),
|
options["filter"].get<std::string>(),
|
||||||
options["sortType"].get<TrackSortType>());
|
options["sortType"].get<TrackSortType>());
|
||||||
result->ExtractLimitAndOffsetFromDeserializedQuery(options);
|
result->ExtractLimitAndOffsetFromDeserializedQuery(options);
|
||||||
|
@ -45,6 +45,7 @@ namespace musik { namespace core { namespace library { namespace query {
|
|||||||
|
|
||||||
SearchTrackListQuery(
|
SearchTrackListQuery(
|
||||||
musik::core::ILibraryPtr library,
|
musik::core::ILibraryPtr library,
|
||||||
|
MatchType matchType,
|
||||||
const std::string& filter,
|
const std::string& filter,
|
||||||
TrackSortType sort);
|
TrackSortType sort);
|
||||||
|
|
||||||
@ -70,6 +71,7 @@ namespace musik { namespace core { namespace library { namespace query {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
musik::core::ILibraryPtr library;
|
musik::core::ILibraryPtr library;
|
||||||
|
MatchType matchType;
|
||||||
bool parseHeaders;
|
bool parseHeaders;
|
||||||
std::string orderBy;
|
std::string orderBy;
|
||||||
std::string orderByPredicate;
|
std::string orderByPredicate;
|
||||||
|
@ -71,10 +71,10 @@ namespace musik { namespace core { namespace library { namespace query {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const std::string REGULAR_PREDICATE = " tracks.{{fk_id}}=? ";
|
static const std::string REGULAR_PREDICATE = " tracks.{{fk_id}}=? ";
|
||||||
static const std::string REGULAR_FILTER = " AND LOWER({{table}}.name) LIKE ? ";
|
static const std::string REGULAR_FILTER = " AND LOWER({{table}}.name) {{match_type}} ? ";
|
||||||
|
|
||||||
static const std::string EXTENDED_PREDICATE = " (key=? AND meta_value_id=?) ";
|
static const std::string EXTENDED_PREDICATE = " (key=? AND meta_value_id=?) ";
|
||||||
static const std::string EXTENDED_FILTER = " AND LOWER(extended_metadata.value) LIKE ?";
|
static const std::string EXTENDED_FILTER = " AND LOWER(extended_metadata.value) {{match_type}} ?";
|
||||||
|
|
||||||
static const std::string EXTENDED_INNER_JOIN =
|
static const std::string EXTENDED_INNER_JOIN =
|
||||||
"INNER JOIN ( "
|
"INNER JOIN ( "
|
||||||
@ -193,7 +193,7 @@ namespace musik { namespace core { namespace library { namespace query {
|
|||||||
and other supplementary information. */
|
and other supplementary information. */
|
||||||
|
|
||||||
static const std::string ALBUM_LIST_FILTER =
|
static const std::string ALBUM_LIST_FILTER =
|
||||||
" AND (LOWER(album) like ? OR LOWER(album_artist) like ?) ";
|
" AND (LOWER(album) LIKE ? OR LOWER(album_artist) LIKE ?) ";
|
||||||
|
|
||||||
static const std::string ALBUM_LIST_QUERY =
|
static const std::string ALBUM_LIST_QUERY =
|
||||||
"SELECT DISTINCT "
|
"SELECT DISTINCT "
|
||||||
|
@ -149,7 +149,11 @@ void TrackSearchLayout::Requery() {
|
|||||||
const std::string& filter = this->input->GetText();
|
const std::string& filter = this->input->GetText();
|
||||||
const TrackSortType sortOrder = getDefaultTrackSort(this->prefs);
|
const TrackSortType sortOrder = getDefaultTrackSort(this->prefs);
|
||||||
this->trackList->Requery(std::shared_ptr<TrackListQueryBase>(
|
this->trackList->Requery(std::shared_ptr<TrackListQueryBase>(
|
||||||
new SearchTrackListQuery(this->library, filter, sortOrder)));
|
new SearchTrackListQuery(
|
||||||
|
this->library,
|
||||||
|
SearchTrackListQuery::MatchType::Substring,
|
||||||
|
filter,
|
||||||
|
sortOrder)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackSearchLayout::PlayFromTop() {
|
void TrackSearchLayout::PlayFromTop() {
|
||||||
|
@ -151,8 +151,8 @@ static void queryPlaylists(
|
|||||||
ILibraryPtr library,
|
ILibraryPtr library,
|
||||||
std::function<void(std::shared_ptr<CategoryListQuery>)> callback)
|
std::function<void(std::shared_ptr<CategoryListQuery>)> callback)
|
||||||
{
|
{
|
||||||
std::shared_ptr<CategoryListQuery> query(
|
std::shared_ptr<CategoryListQuery> query(new CategoryListQuery(
|
||||||
new CategoryListQuery(Playlists::TABLE_NAME, ""));
|
CategoryListQuery::MatchType::Substring, Playlists::TABLE_NAME, ""));
|
||||||
|
|
||||||
library->Enqueue(query, [callback, query](auto q) {
|
library->Enqueue(query, [callback, query](auto q) {
|
||||||
callback(query->GetStatus() == IQuery::Finished
|
callback(query->GetStatus() == IQuery::Finished
|
||||||
|
@ -109,7 +109,8 @@ void CategoryListView::RequeryWithField(
|
|||||||
this->fieldIdColumn = getFieldIdColumn(fieldName);
|
this->fieldIdColumn = getFieldIdColumn(fieldName);
|
||||||
this->selectAfterQuery = selectAfterQuery;
|
this->selectAfterQuery = selectAfterQuery;
|
||||||
this->filter = filter;
|
this->filter = filter;
|
||||||
this->activeQuery.reset(new CategoryListQuery(fieldName, filter));
|
this->activeQuery.reset(new CategoryListQuery(
|
||||||
|
CategoryListQuery::MatchType::Substring, fieldName, filter));
|
||||||
this->library->Enqueue(activeQuery);
|
this->library->Enqueue(activeQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user