Clementine-audio-player-Mac.../src/library/libraryquery.cpp

173 lines
5.0 KiB
C++
Raw Normal View History

/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
2009-12-24 20:16:07 +01:00
#include "libraryquery.h"
#include "core/song.h"
2009-12-24 20:16:07 +01:00
#include <QtDebug>
#include <QDateTime>
#include <QSqlError>
QueryOptions::QueryOptions()
: max_age(-1),
duplicates_only(false)
2009-12-24 20:16:07 +01:00
{
}
LibraryQuery::LibraryQuery(const QueryOptions& options)
: join_with_fts_(false),
limit_(-1)
{
2009-12-24 20:16:07 +01:00
if (!options.filter.isEmpty()) {
// We need to munge the filter text a little bit to get it to work as
// expected with sqlite's FTS3:
// 1) Append * to all tokens.
// 2) Prefix "fts" to column names.
// Split on whitespace
QStringList tokens(options.filter.split(QRegExp("\\s+")));
QString query;
foreach (QString token, tokens) {
token.remove('(');
token.remove(')');
if (token.contains(':'))
query += "fts" + token + "* ";
else
query += token + "* ";
}
2010-11-27 20:37:09 +01:00
where_clauses_ << "fts.%fts_table_noprefix MATCH ?";
bound_values_ << query;
join_with_fts_ = true;
2009-12-24 20:16:07 +01:00
}
if (options.max_age != -1) {
int cutoff = QDateTime::currentDateTime().toTime_t() - options.max_age;
where_clauses_ << "ctime > ?";
bound_values_ << cutoff;
}
duplicates_only_ = false;
if(options.duplicates_only) {
// TODO: currently you cannot use the duplicates_only flag and fts at the same time.
// joining songs, duplicated_songs and songs_fts all together takes a huge amount of
// time. the query takes about 20 seconds then. why?
Q_ASSERT(!join_with_fts_);
duplicates_only_ = true;
}
}
QString LibraryQuery::GetInnerQuery() {
return duplicates_only_
? QString(" INNER JOIN (select * from duplicated_songs) dsongs "
"ON (%songs_table.artist = dsongs.dup_artist "
"AND %songs_table.album = dsongs.dup_album "
"AND %songs_table.title = dsongs.dup_title) ")
: QString();
2009-12-24 20:16:07 +01:00
}
void LibraryQuery::AddWhere(const QString& column, const QVariant& value,
const QString& op) {
// ignore 'literal' for IN
if(!op.compare("IN", Qt::CaseInsensitive)) {
QStringList final;
foreach(const QString& single_value, value.toStringList()) {
final.append("?");
bound_values_ << single_value;
}
where_clauses_ << QString("%1 IN (" + final.join(",") + ")").arg(column);
} else {
// Do integers inline - sqlite seems to get confused when you pass integers
// to bound parameters
if(value.type() == QVariant::Int) {
where_clauses_ << QString("%1 %2 %3").arg(column, op, value.toString());
} else {
where_clauses_ << QString("%1 %2 ?").arg(column, op);
bound_values_ << value;
}
2009-12-24 20:16:07 +01:00
}
}
void LibraryQuery::AddCompilationRequirement(bool compilation) {
where_clauses_ << QString("effective_compilation = %1").arg(compilation ? 1 : 0);
}
QSqlQuery LibraryQuery::Exec(QSqlDatabase db, const QString& songs_table,
const QString& fts_table) {
QString sql;
if (join_with_fts_) {
sql = QString("SELECT %1 FROM %2 INNER JOIN %3 AS fts ON %2.ROWID = fts.ROWID")
.arg(column_spec_, songs_table, fts_table);
} else {
sql = QString("SELECT %1 FROM %2 %3")
.arg(column_spec_, songs_table, GetInnerQuery());
}
2009-12-24 20:16:07 +01:00
if (!where_clauses_.isEmpty())
sql += " WHERE " + where_clauses_.join(" AND ");
if (!order_by_.isEmpty())
sql += " ORDER BY " + order_by_;
if (limit_ != -1)
sql += " LIMIT " + QString::number(limit_);
sql.replace("%songs_table", songs_table);
2010-11-27 20:37:09 +01:00
sql.replace("%fts_table_noprefix", fts_table.section('.', -1, -1));
sql.replace("%fts_table", fts_table);
query_ = QSqlQuery(sql, db);
2009-12-24 20:16:07 +01:00
// Bind values
foreach (const QVariant& value, bound_values_) {
query_.addBindValue(value);
2009-12-24 20:16:07 +01:00
}
query_.exec();
return query_;
}
bool LibraryQuery::Next() {
return query_.next();
}
QVariant LibraryQuery::Value(int column) const {
return query_.value(column);
2009-12-24 20:16:07 +01:00
}
bool QueryOptions::Matches(const Song& song) const {
if (max_age != -1) {
const uint cutoff = QDateTime::currentDateTime().toTime_t() - max_age;
if (song.ctime() <= cutoff)
return false;
}
if (!filter.isNull()) {
return song.artist().contains(filter, Qt::CaseInsensitive) ||
song.album().contains(filter, Qt::CaseInsensitive) ||
song.title().contains(filter, Qt::CaseInsensitive);
}
return true;
}