Genre.cpp 7.47 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

23 24 25 26
#if HAVE_CONFIG_H
# include "config.h"
#endif

27 28
#include "Genre.h"

29
#include "Album.h"
30
#include "AlbumTrack.h"
31
#include "Artist.h"
32
#include "Media.h"
33
#include "database/SqliteQuery.h"
34

35 36 37
namespace medialibrary
{

38 39 40 41
namespace policy
{
const std::string GenreTable::Name = "Genre";
const std::string GenreTable::PrimaryKeyColumn = "id_genre";
42
int64_t Genre::* const GenreTable::PrimaryKey = &Genre::m_id;
43 44
}

45 46
Genre::Genre( MediaLibraryPtr ml, sqlite::Row& row )
    : m_ml( ml )
47 48
{
    row >> m_id
49 50
        >> m_name
        >> m_nbTracks;
51 52
}

53 54
Genre::Genre( MediaLibraryPtr ml, const std::string& name )
    : m_ml( ml )
55
    , m_id( 0 )
56
    , m_name( name )
57
    , m_nbTracks( 0 )
58 59 60
{
}

61
int64_t Genre::id() const
62 63 64 65 66 67 68 69 70
{
    return m_id;
}

const std::string& Genre::name() const
{
    return m_name;
}

71 72 73 74 75 76 77 78 79 80
uint32_t Genre::nbTracks() const
{
    return m_nbTracks;
}

void Genre::updateCachedNbTracks( int increment )
{
    m_nbTracks += increment;
}

81
Query<IArtist> Genre::artists( const QueryParameters* params ) const
82
{
83
    std::string req = "FROM " + policy::ArtistTable::Name + " a "
84
            "INNER JOIN " + policy::AlbumTrackTable::Name + " att ON att.artist_id = a.id_artist "
85 86
            "WHERE att.genre_id = ? GROUP BY att.artist_id"
            " ORDER BY a.name";
87
    if ( params != nullptr && params->desc == true )
88
        req += " DESC";
89
    return make_query<Artist, IArtist>( m_ml, "a.*", std::move( req ), m_id );
90 91
}

92
Query<IArtist> Genre::searchArtists( const std::string& pattern,
93 94 95 96 97
                                    const QueryParameters* params ) const
{
    return Artist::searchByGenre( m_ml, pattern, params, m_id );
}

98
Query<IMedia> Genre::tracks( const QueryParameters* params ) const
99
{
100
    return AlbumTrack::fromGenre( m_ml, m_id, params );
101 102
}

103 104 105 106 107
Query<IMedia> Genre::searchTracks( const std::string& pattern, const QueryParameters* params ) const
{
    return Media::searchGenreTracks( m_ml, pattern, m_id, params );
}

108
Query<IAlbum> Genre::albums( const QueryParameters* params ) const
109
{
110
    return Album::fromGenre( m_ml, m_id, params );
111 112
}

113 114 115 116 117 118
Query<IAlbum> Genre::searchAlbums( const std::string& pattern,
                                   const QueryParameters* params ) const
{
    return Album::searchFromGenre( m_ml, pattern, m_id, params );
}

119
void Genre::createTable( sqlite::Connection* dbConn )
120
{
121
    const std::string req = "CREATE TABLE IF NOT EXISTS " + policy::GenreTable::Name +
122 123
        "("
            "id_genre INTEGER PRIMARY KEY AUTOINCREMENT,"
124
            "name TEXT COLLATE NOCASE UNIQUE ON CONFLICT FAIL,"
125
            "nb_tracks INTEGER NOT NULL DEFAULT 0"
126
        ")";
127
    const std::string vtableReq = "CREATE VIRTUAL TABLE IF NOT EXISTS "
128 129 130 131
                + policy::GenreTable::Name + "Fts USING FTS3("
                "name"
            ")";

132 133 134 135 136 137
    sqlite::Tools::executeRequest( dbConn, req );
    sqlite::Tools::executeRequest( dbConn, vtableReq );
}

void Genre::createTriggers( sqlite::Connection* dbConn )
{
138
    const std::string vtableInsertTrigger = "CREATE TRIGGER IF NOT EXISTS insert_genre_fts"
139 140 141 142
            " AFTER INSERT ON " + policy::GenreTable::Name +
            " BEGIN"
            " INSERT INTO " + policy::GenreTable::Name + "Fts(rowid,name) VALUES(new.id_genre, new.name);"
            " END";
143
    const std::string vtableDeleteTrigger = "CREATE TRIGGER IF NOT EXISTS delete_genre_fts"
144 145 146 147
            " BEFORE DELETE ON " + policy::GenreTable::Name +
            " BEGIN"
            " DELETE FROM " + policy::GenreTable::Name + "Fts WHERE rowid = old.id_genre;"
            " END";
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    const std::string onGenreChanged = "CREATE TRIGGER IF NOT EXISTS on_track_genre_changed AFTER UPDATE OF "
            " genre_id ON " + policy::AlbumTrackTable::Name +
            " BEGIN"
            " UPDATE " + policy::GenreTable::Name + " SET nb_tracks = nb_tracks + 1 WHERE id_genre = new.genre_id;"
            " UPDATE " + policy::GenreTable::Name + " SET nb_tracks = nb_tracks - 1 WHERE id_genre = old.genre_id;"
            " DELETE FROM " + policy::GenreTable::Name + " WHERE nb_tracks = 0;"
            " END";
    const std::string onTrackCreated = "CREATE TRIGGER IF NOT EXISTS update_genre_on_new_track"
            " AFTER INSERT ON " + policy::AlbumTrackTable::Name +
            " WHEN new.genre_id IS NOT NULL"
            " BEGIN"
            " UPDATE " + policy::GenreTable::Name + " SET nb_tracks = nb_tracks + 1 WHERE id_genre = new.genre_id;"
            " END";
    const std::string onTrackDeleted = "CREATE TRIGGER IF NOT EXISTS update_genre_on_track_deleted"
            " AFTER DELETE ON " + policy::AlbumTrackTable::Name +
            " WHEN old.genre_id IS NOT NULL"
            " BEGIN"
            " UPDATE " + policy::GenreTable::Name + " SET nb_tracks = nb_tracks - 1 WHERE id_genre = old.genre_id;"
            " DELETE FROM " + policy::GenreTable::Name + " WHERE nb_tracks = 0;"
            " END";

169 170
    sqlite::Tools::executeRequest( dbConn, vtableInsertTrigger );
    sqlite::Tools::executeRequest( dbConn, vtableDeleteTrigger );
171 172 173
    sqlite::Tools::executeRequest( dbConn, onGenreChanged );
    sqlite::Tools::executeRequest( dbConn, onTrackCreated );
    sqlite::Tools::executeRequest( dbConn, onTrackDeleted );
174 175
}

176
std::shared_ptr<Genre> Genre::create( MediaLibraryPtr ml, const std::string& name )
177 178 179
{
    static const std::string req = "INSERT INTO " + policy::GenreTable::Name + "(name)"
            "VALUES(?)";
180
    auto self = std::make_shared<Genre>( ml, name );
181
    if ( insert( ml, self, req, name ) == false )
182 183 184 185
        return nullptr;
    return self;
}

186
std::shared_ptr<Genre> Genre::fromName( MediaLibraryPtr ml, const std::string& name )
187 188
{
    static const std::string req = "SELECT * FROM " + policy::GenreTable::Name + " WHERE name = ?";
189
    return fetch( ml, req, name );
190 191
}

192 193
Query<IGenre> Genre::search( MediaLibraryPtr ml, const std::string& name,
                             const QueryParameters* params )
194
{
195 196
    std::string req = "FROM " + policy::GenreTable::Name + " WHERE id_genre IN "
            "(SELECT rowid FROM " + policy::GenreTable::Name + "Fts WHERE name MATCH '*' || ? || '*') ORDER BY name";
197
    if ( params != nullptr && params->desc == true )
198
        req += " DESC";
199
    return make_query<Genre, IGenre>( ml, "*", req, name );
200 201
}

202
Query<IGenre> Genre::listAll( MediaLibraryPtr ml, const QueryParameters* params )
203
{
204
    std::string req = "FROM " + policy::GenreTable::Name + " ORDER BY name";
205
    if ( params != nullptr && params->desc == true )
206
        req += " DESC";
207
    return make_query<Genre, IGenre>( ml, "*", std::move( req ) );
208 209
}

210
}