1 /*
2  * Strawberry Music Player
3  * This file was part of Clementine.
4  * Copyright 2010, David Sansome <me@davidsansome.com>
5  * Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net>
6  *
7  * Strawberry is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Strawberry is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Strawberry.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef COLLECTIONQUERY_H
23 #define COLLECTIONQUERY_H
24 
25 #include "config.h"
26 
27 #include <QMetaType>
28 #include <QVariant>
29 #include <QString>
30 #include <QStringList>
31 #include <QMap>
32 #include <QSqlDatabase>
33 #include <QSqlQuery>
34 
35 class Song;
36 
37 // This structure let's you customize behaviour of any CollectionQuery.
38 struct QueryOptions {
39   // Modes of CollectionQuery:
40   // - use the all songs table
41   // - use the duplicated songs view; by duplicated we mean those songs for which the (artist, album, title) tuple is found more than once in the songs table
42   // - use the untagged songs view; by untagged we mean those for which at least one of the (artist, album, title) tags is empty
43   // Please note that additional filtering based on FTS table (the filter attribute) won't work in Duplicates and Untagged modes.
44   enum QueryMode {
45     QueryMode_All,
46     QueryMode_Duplicates,
47     QueryMode_Untagged
48   };
49 
50   QueryOptions();
51 
52   bool Matches(const Song &song) const;
53 
filterQueryOptions54   QString filter() const { return filter_; }
set_filterQueryOptions55   void set_filter(const QString &filter) {
56     filter_ = filter;
57     query_mode_ = QueryMode_All;
58   }
59 
max_ageQueryOptions60   int max_age() const { return max_age_; }
set_max_ageQueryOptions61   void set_max_age(int max_age) { max_age_ = max_age; }
62 
query_modeQueryOptions63   QueryMode query_mode() const { return query_mode_; }
set_query_modeQueryOptions64   void set_query_mode(QueryMode query_mode) {
65     query_mode_ = query_mode;
66     filter_ = QString();
67   }
68 
69  private:
70   QString filter_;
71   int max_age_;
72   QueryMode query_mode_;
73 };
74 
75 class CollectionQuery : public QSqlQuery {
76  public:
77   explicit CollectionQuery(const QSqlDatabase &db, const QString &songs_table, const QString &fts_table, const QueryOptions &options = QueryOptions());
78 
79   // Sets contents of SELECT clause on the query (list of columns to get).
SetColumnSpec(const QString & spec)80   void SetColumnSpec(const QString &spec) { column_spec_ = spec; }
81 
82   // Sets an ORDER BY clause on the query.
SetOrderBy(const QString & order_by)83   void SetOrderBy(const QString &order_by) { order_by_ = order_by; }
84 
85   // Adds a fragment of WHERE clause. When executed, this Query will connect all the fragments with AND operator.
86   // Please note that IN operator expects a QStringList as value.
87   void AddWhere(const QString &column, const QVariant &value, const QString &op = "=");
88   void AddWhereArtist(const QVariant &value);
89 
SetWhereClauses(const QStringList & where_clauses)90   void SetWhereClauses(const QStringList &where_clauses) { where_clauses_ = where_clauses; }
SetBoundValues(const QVariantList & bound_values)91   void SetBoundValues(const QVariantList &bound_values) { bound_values_ = bound_values; }
SetDuplicatesOnly(const bool duplicates_only)92   void SetDuplicatesOnly(const bool duplicates_only) { duplicates_only_ = duplicates_only; }
SetIncludeUnavailable(const bool include_unavailable)93   void SetIncludeUnavailable(const bool include_unavailable) { include_unavailable_ = include_unavailable; }
SetLimit(const int limit)94   void SetLimit(const int limit) { limit_ = limit; }
95   void AddCompilationRequirement(const bool compilation);
96 
97   bool Exec();
98   bool Next();
99   QVariant Value(const int column) const;
100 
column_spec()101   QString column_spec() const { return column_spec_; }
order_by()102   QString order_by() const { return order_by_; }
where_clauses()103   QStringList where_clauses() const { return where_clauses_; }
bound_values()104   QVariantList bound_values() const { return bound_values_; }
include_unavailable()105   bool include_unavailable() const { return include_unavailable_; }
join_with_fts()106   bool join_with_fts() const { return join_with_fts_; }
duplicates_only()107   bool duplicates_only() const { return duplicates_only_; }
limit()108   int limit() const { return limit_; }
109 
110  private:
111   QString GetInnerQuery() const;
112 
113   QSqlDatabase db_;
114   QString songs_table_;
115   QString fts_table_;
116 
117   QString column_spec_;
118   QString order_by_;
119   QStringList where_clauses_;
120   QVariantList bound_values_;
121 
122   bool include_unavailable_;
123   bool join_with_fts_;
124   bool duplicates_only_;
125   int limit_;
126 };
127 
128 #endif // COLLECTIONQUERY_H
129