More columns for use in library search queries

Support more columns for the COLUMN:VALUE syntax
in the library search query
This commit is contained in:
Ilgiz Mustafin 2018-09-04 19:51:33 +03:00 committed by John Maguire
parent 8902776b32
commit 8818ba340a
4 changed files with 65 additions and 13 deletions

View File

@ -118,6 +118,19 @@ const QStringList Song::kColumns = QStringList() << "title"
<< "originalyear" << "originalyear"
<< "effective_originalyear"; << "effective_originalyear";
const QStringList Song::kIntColumns = QStringList() << "track"
<< "disc"
<< "year"
<< "originalyear"
<< "playcount"
<< "skipcount"
<< "score"
<< "bitrate"
<< "samplerate";
const QStringList Song::kFloatColumns = QStringList() << "rating" << "bpm";
const QString Song::kColumnSpec = Song::kColumns.join(", "); const QString Song::kColumnSpec = Song::kColumns.join(", ");
const QString Song::kBindSpec = const QString Song::kBindSpec =
Utilities::Prepend(":", Song::kColumns).join(", "); Utilities::Prepend(":", Song::kColumns).join(", ");

View File

@ -73,6 +73,9 @@ class Song {
static const QString kBindSpec; static const QString kBindSpec;
static const QString kUpdateSpec; static const QString kUpdateSpec;
static const QStringList kIntColumns;
static const QStringList kFloatColumns;
static const QStringList kFtsColumns; static const QStringList kFtsColumns;
static const QString kFtsColumnSpec; static const QString kFtsColumnSpec;
static const QString kFtsBindSpec; static const QString kFtsBindSpec;

View File

@ -24,6 +24,12 @@
QueryOptions::QueryOptions() : max_age_(-1), query_mode_(QueryMode_All) {} QueryOptions::QueryOptions() : max_age_(-1), query_mode_(QueryMode_All) {}
const QStringList LibraryQuery::kNumericCompOperators = QStringList() << "<="
<< ">="
<< "<"
<< ">"
<< "=";
LibraryQuery::LibraryQuery(const QueryOptions& options) LibraryQuery::LibraryQuery(const QueryOptions& options)
: include_unavailable_(false), join_with_fts_(false), limit_(-1) { : include_unavailable_(false), join_with_fts_(false), limit_(-1) {
if (!options.filter().isEmpty()) { if (!options.filter().isEmpty()) {
@ -32,6 +38,9 @@ LibraryQuery::LibraryQuery(const QueryOptions& options)
// 1) Append * to all tokens. // 1) Append * to all tokens.
// 2) Prefix "fts" to column names. // 2) Prefix "fts" to column names.
// 3) Remove colons which don't correspond to column names. // 3) Remove colons which don't correspond to column names.
//
// We also allow to search on non-FTS columns, but FTS columns
// are higher priority. Non-FTS query parts go to where_clauses
// Split on whitespace // Split on whitespace
QStringList tokens( QStringList tokens(
@ -44,17 +53,40 @@ LibraryQuery::LibraryQuery(const QueryOptions& options)
token.replace('-', ' '); token.replace('-', ' ');
if (token.contains(':')) { if (token.contains(':')) {
// Only prefix fts if the token is a valid column name. QString columntoken = token.section(':', 0, 0);
if (Song::kFtsColumns.contains("fts" + token.section(':', 0, 0), QString subtoken = token.section(':', 1, -1);
Qt::CaseInsensitive)) { subtoken.replace(":", " ");
// Account for multiple colons. subtoken = subtoken.trimmed();
QString columntoken =
token.section(':', 0, 0, QString::SectionIncludeTrailingSep); if (Song::kFtsColumns.contains("fts" + columntoken,
QString subtoken = token.section(':', 1, -1); Qt::CaseInsensitive)) { // Is it a FTS column?
subtoken.replace(":", " ");
subtoken = subtoken.trimmed();
query += "fts" + columntoken + subtoken + "* "; query += "fts" + columntoken + subtoken + "* ";
} else { } else if (Song::kColumns.contains(columntoken, Qt::CaseInsensitive)) {
// We need to extract the operator and the value from the subtoken
QRegExp operatorRe("^(" + kNumericCompOperators.join("|") + ")(.*)");
QString op = "="; // default if no operator given
QString val = subtoken; // whole subtoken is the value if no operator
if (operatorRe.indexIn(subtoken) != -1) {
op = operatorRe.cap(1);
val = operatorRe.cap(2);
}
if (Song::kIntColumns.contains(columntoken)) {
bool ok;
int intVal = val.toInt(&ok);
if (ok) {
AddWhere(columntoken, intVal, op);
}
} else if (Song::kFloatColumns.contains(columntoken)) {
bool ok;
double doubleVal = val.toDouble(&ok);
if (ok) {
AddWhere(columntoken, doubleVal, op);
}
} else {
AddWhere(columntoken, val, op);
}
} else { // We did't recognize this as a column
token.replace(":", " "); token.replace(":", " ");
token = token.trimmed(); token = token.trimmed();
query += token + "* "; query += token + "* ";
@ -64,9 +96,11 @@ LibraryQuery::LibraryQuery(const QueryOptions& options)
} }
} }
where_clauses_ << "fts.%fts_table_noprefix MATCH ?"; if (!query.isEmpty()) {
bound_values_ << query; where_clauses_ << "fts.%fts_table_noprefix MATCH ?";
join_with_fts_ = true; bound_values_ << query;
join_with_fts_ = true;
}
} }
if (options.max_age() != -1) { if (options.max_age() != -1) {

View File

@ -93,6 +93,8 @@ class LibraryQuery {
operator const QSqlQuery&() const { return query_; } operator const QSqlQuery&() const { return query_; }
static const QStringList kNumericCompOperators;
private: private:
QString GetInnerQuery(); QString GetInnerQuery();