Commit f13fb525 authored by Jian Li's avatar Jian Li
Browse files

Merge branch 'sortfilename' of code.videolan.org:ilearninging/medialibrary into sortfilename

parents 76a0152d 318ac801
Pipeline #12020 passed with stage
in 20 minutes and 10 seconds
......@@ -414,14 +414,8 @@ EXTRA_DIST += medialibrary.pc \
src/database/migrations/migration19-20.sql \
src/database/migrations/migration20-21.sql \
src/database/migrations/migration21-22.sql \
src/database/tables/File_triggers_v14.sql \
src/database/tables/Folder_triggers_v14.sql \
src/database/tables/Folder_triggers_v15.sql \
src/database/tables/Playlist_triggers_v14.sql \
src/database/tables/Playlist_triggers_v16.sql \
src/database/tables/Task_triggers_v18.sql \
src/database/tables/Thumbnail_triggers_v17.sql \
src/database/tables/Thumbnail_triggers_v18.sql \
src/database/migrations/migration22-23.sql \
src/database/migrations/migration23-24.sql \
$(NULL)
......
......@@ -479,9 +479,9 @@ public:
* - NbAudio
* - NbMedia
*/
virtual Query<IMediaGroup> mediaGroups( const QueryParameters* params ) const = 0;
virtual Query<IMediaGroup> mediaGroups( const QueryParameters* params = nullptr ) const = 0;
virtual Query<IMediaGroup> searchMediaGroups( const std::string& pattern,
const QueryParameters* params ) const = 0;
const QueryParameters* params = nullptr ) const = 0;
virtual AlbumPtr album( int64_t id ) const = 0;
virtual Query<IAlbum> albums( const QueryParameters* params = nullptr ) const = 0;
virtual ShowPtr show( int64_t id ) const = 0;
......
......@@ -507,81 +507,22 @@ void Album::createTable( sqlite::Connection* dbConnection )
void Album::createTriggers( sqlite::Connection* dbConnection, uint32_t dbModelVersion )
{
const std::string indexReq = "CREATE INDEX IF NOT EXISTS album_artist_id_idx ON " +
Table::Name + "(artist_id)";
if ( dbModelVersion < 23 )
{
static const std::string triggerReq = "CREATE TRIGGER IF NOT EXISTS is_album_present AFTER UPDATE OF "
"is_present ON " + Media::Table::Name +
" WHEN new.subtype = " +
std::to_string( static_cast<typename std::underlying_type<IMedia::SubType>::type>(
IMedia::SubType::AlbumTrack ) ) +
" BEGIN "
" UPDATE " + Table::Name + " SET is_present=is_present + "
"(CASE new.is_present WHEN 0 THEN -1 ELSE 1 END)"
"WHERE id_album = (SELECT album_id FROM " + AlbumTrack::Table::Name + " "
"WHERE media_id = new.id_media"
");"
" END";
sqlite::Tools::executeRequest( dbConnection, triggerReq );
}
else
{
static const std::string triggerReq = "CREATE TRIGGER IF NOT EXISTS album_is_present AFTER UPDATE OF "
"is_present ON " + Media::Table::Name +
" WHEN new.subtype = " +
std::to_string( static_cast<typename std::underlying_type<IMedia::SubType>::type>(
IMedia::SubType::AlbumTrack ) ) +
" AND old.is_present != new.is_present"
" BEGIN "
" UPDATE " + Table::Name + " SET is_present=is_present + "
"(CASE new.is_present WHEN 0 THEN -1 ELSE 1 END)"
"WHERE id_album = (SELECT album_id FROM " + AlbumTrack::Table::Name + " "
"WHERE media_id = new.id_media"
");"
" END";
sqlite::Tools::executeRequest( dbConnection, triggerReq );
}
static const std::string deleteTriggerReq = "CREATE TRIGGER IF NOT EXISTS delete_album_track AFTER DELETE ON "
+ AlbumTrack::Table::Name +
" BEGIN "
" UPDATE " + Table::Name +
" SET"
" nb_tracks = nb_tracks - 1,"
" is_present = is_present - 1,"
" duration = duration - old.duration"
" WHERE id_album = old.album_id;"
" DELETE FROM " + Table::Name +
" WHERE id_album=old.album_id AND nb_tracks = 0;"
" END";
static const std::string updateAddTrackTriggerReq = "CREATE TRIGGER IF NOT EXISTS add_album_track"
" AFTER INSERT ON " + AlbumTrack::Table::Name +
" BEGIN"
" UPDATE " + Table::Name +
" SET duration = duration + new.duration,"
" nb_tracks = nb_tracks + 1,"
" is_present = is_present + 1"
" WHERE id_album = new.album_id;"
" END";
static const std::string vtriggerInsert = "CREATE TRIGGER IF NOT EXISTS insert_album_fts AFTER INSERT ON "
+ Table::Name +
// Skip unknown albums
" WHEN new.title IS NOT NULL"
" BEGIN"
" INSERT INTO " + FtsTable::Name + "(rowid, title) VALUES(new.id_album, new.title);"
" END";
static const std::string vtriggerDelete = "CREATE TRIGGER IF NOT EXISTS delete_album_fts BEFORE DELETE ON "
+ Table::Name +
// Unknown album probably won't be deleted, but better safe than sorry
" WHEN old.title IS NOT NULL"
" BEGIN"
" DELETE FROM " + FtsTable::Name + " WHERE rowid = old.id_album;"
" END";
sqlite::Tools::executeRequest( dbConnection, indexReq );
sqlite::Tools::executeRequest( dbConnection, deleteTriggerReq );
sqlite::Tools::executeRequest( dbConnection, updateAddTrackTriggerReq );
sqlite::Tools::executeRequest( dbConnection, vtriggerInsert );
sqlite::Tools::executeRequest( dbConnection, vtriggerDelete );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::IsPresent, dbModelVersion ) );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::DeleteTrack, dbModelVersion ) );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::AddTrack, dbModelVersion ) );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::InsertFts, dbModelVersion ) );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::DeleteFts, dbModelVersion ) );
}
void Album::createIndexes( sqlite::Connection* dbConnection, uint32_t dbModelVersion )
{
sqlite::Tools::executeRequest( dbConnection,
index( Indexes::ArtistId, dbModelVersion ) );
}
std::string Album::schema( const std::string& tableName, uint32_t dbModel )
......@@ -642,14 +583,160 @@ std::string Album::schema( const std::string& tableName, uint32_t dbModel )
return "<not a valid request>";
}
std::string Album::trigger( Triggers trigger, uint32_t dbModel )
{
switch ( trigger )
{
case Triggers::IsPresent:
{
if ( dbModel < 23 )
{
return "CREATE TRIGGER " + triggerName( trigger, dbModel ) +
" AFTER UPDATE OF is_present ON " + Media::Table::Name +
" WHEN new.subtype = " +
std::to_string( static_cast<typename std::underlying_type<IMedia::SubType>::type>(
IMedia::SubType::AlbumTrack ) ) +
" BEGIN "
" UPDATE " + Table::Name + " SET is_present=is_present + "
"(CASE new.is_present WHEN 0 THEN -1 ELSE 1 END)"
"WHERE id_album = (SELECT album_id FROM " + AlbumTrack::Table::Name + " "
"WHERE media_id = new.id_media"
");"
" END";
}
else
{
return "CREATE TRIGGER " + triggerName( trigger, dbModel ) +
" AFTER UPDATE OF is_present ON " + Media::Table::Name +
" WHEN new.subtype = " +
std::to_string( static_cast<typename std::underlying_type<IMedia::SubType>::type>(
IMedia::SubType::AlbumTrack ) ) +
" AND old.is_present != new.is_present"
" BEGIN "
" UPDATE " + Table::Name + " SET is_present=is_present + "
"(CASE new.is_present WHEN 0 THEN -1 ELSE 1 END)"
"WHERE id_album = (SELECT album_id FROM " + AlbumTrack::Table::Name + " "
"WHERE media_id = new.id_media"
");"
" END";
}
}
case Triggers::AddTrack:
{
return "CREATE TRIGGER " + triggerName( trigger, dbModel ) +
" AFTER INSERT ON " + AlbumTrack::Table::Name +
" BEGIN"
" UPDATE " + Table::Name +
" SET duration = duration + new.duration,"
" nb_tracks = nb_tracks + 1,"
" is_present = is_present + 1"
" WHERE id_album = new.album_id;"
" END";
}
case Triggers::DeleteTrack:
{
return "CREATE TRIGGER " + triggerName( trigger, dbModel ) +
" AFTER DELETE ON " + AlbumTrack::Table::Name +
" BEGIN "
" UPDATE " + Table::Name +
" SET"
" nb_tracks = nb_tracks - 1,"
" is_present = is_present - 1,"
" duration = duration - old.duration"
" WHERE id_album = old.album_id;"
" DELETE FROM " + Table::Name +
" WHERE id_album=old.album_id AND nb_tracks = 0;"
" END";
}
case Triggers::InsertFts:
{
return "CREATE TRIGGER " + triggerName( trigger, dbModel ) +
" AFTER INSERT ON " + Table::Name +
// Skip unknown albums
" WHEN new.title IS NOT NULL"
" BEGIN"
" INSERT INTO " + FtsTable::Name + "(rowid, title)"
" VALUES(new.id_album, new.title);"
" END";
}
case Triggers::DeleteFts:
{
return "CREATE TRIGGER " + triggerName( trigger, dbModel ) +
" BEFORE DELETE ON " + Table::Name +
// Unknown album probably won't be deleted, but better safe than sorry
" WHEN old.title IS NOT NULL"
" BEGIN"
" DELETE FROM " + FtsTable::Name +
" WHERE rowid = old.id_album;"
" END";
}
default:
assert( !"Invalid trigger provided" );
}
return "<Invalid request provided>";
}
std::string Album::triggerName( Album::Triggers trigger, uint32_t dbModel )
{
switch ( trigger )
{
case Triggers::IsPresent:
{
if ( dbModel < 23 )
return "is_album_present";
return "album_is_present";
}
case Triggers::AddTrack:
return "add_album_track";
case Triggers::DeleteTrack:
return "delete_album_track";
case Triggers::InsertFts:
return "insert_album_fts";
case Triggers::DeleteFts:
return "delete_album_fts";
default:
assert( !"Invalid trigger provided" );
}
}
std::string Album::index( Indexes index, uint32_t dbModel )
{
assert( index == Indexes::ArtistId );
return "CREATE INDEX " + indexName( index, dbModel ) + " ON " +
Table::Name + "(artist_id)";
}
std::string Album::indexName( Album::Indexes index, uint32_t )
{
assert( index == Indexes::ArtistId );
return "album_artist_id_idx";
}
bool Album::checkDbModel( MediaLibraryPtr ml )
{
return sqlite::Tools::checkSchema( ml->getConn(),
if ( sqlite::Tools::checkTableSchema( ml->getConn(),
schema( Table::Name, Settings::DbModelVersion ),
Table::Name ) &&
sqlite::Tools::checkSchema( ml->getConn(),
Table::Name ) == false ||
sqlite::Tools::checkTableSchema( ml->getConn(),
schema( FtsTable::Name, Settings::DbModelVersion ),
FtsTable::Name );
FtsTable::Name ) == false )
return false;
if ( sqlite::Tools::checkIndexStatement( ml->getConn(),
index( Indexes::ArtistId, Settings::DbModelVersion ),
indexName( Indexes::ArtistId, Settings::DbModelVersion ) ) == false )
return false;
auto check = []( sqlite::Connection* dbConn, Triggers t ) {
return sqlite::Tools::checkTriggerStatement( dbConn,
trigger( t, Settings::DbModelVersion ),
triggerName( t, Settings::DbModelVersion ) );
};
return check( ml->getConn(), Triggers::IsPresent ) &&
check( ml->getConn(), Triggers::AddTrack ) &&
check( ml->getConn(), Triggers::DeleteTrack ) &&
check( ml->getConn(), Triggers::InsertFts ) &&
check( ml->getConn(), Triggers::DeleteFts );
}
std::shared_ptr<Album> Album::create( MediaLibraryPtr ml, const std::string& title )
......
......@@ -51,6 +51,18 @@ class Album : public IAlbum, public DatabaseHelpers<Album>
{
static const std::string Name;
};
enum class Triggers : uint8_t
{
IsPresent,
AddTrack,
DeleteTrack,
InsertFts,
DeleteFts,
};
enum class Indexes : uint8_t
{
ArtistId,
};
Album( MediaLibraryPtr ml, sqlite::Row& row );
Album( MediaLibraryPtr ml, const std::string& title );
......@@ -109,7 +121,12 @@ class Album : public IAlbum, public DatabaseHelpers<Album>
static void createTable( sqlite::Connection* dbConnection );
static void createTriggers( sqlite::Connection* dbConnection, uint32_t dbModelVersion );
static void createIndexes( sqlite::Connection* dbConnection, uint32_t dbModelVersion );
static std::string schema( const std::string& tableName, uint32_t dbModel );
static std::string trigger( Triggers trigger, uint32_t dbModel );
static std::string triggerName(Triggers trigger , uint32_t dbModel);
static std::string index( Indexes index, uint32_t dbModel );
static std::string indexName( Indexes index, uint32_t dbModel );
static bool checkDbModel( MediaLibraryPtr ml );
static std::shared_ptr<Album> create( MediaLibraryPtr ml, const std::string& title );
static std::shared_ptr<Album> createUnknownAlbum( MediaLibraryPtr ml, const Artist* artist );
......
......@@ -91,16 +91,12 @@ void AlbumTrack::createTable( sqlite::Connection* dbConnection )
Settings::DbModelVersion ) );
}
void AlbumTrack::createTriggers(sqlite::Connection* dbConnection)
void AlbumTrack::createIndexes( sqlite::Connection* dbConnection )
{
const std::string indexReq = "CREATE INDEX IF NOT EXISTS "
"album_media_artist_genre_album_idx ON " +
AlbumTrack::Table::Name +
"(media_id, artist_id, genre_id, album_id)";
const std::string indexAlbumIdReq = "CREATE INDEX IF NOT EXISTS album_track_album_genre_artist_ids "
"ON " + AlbumTrack::Table::Name + "(album_id, genre_id, artist_id)";
sqlite::Tools::executeRequest( dbConnection, indexReq );
sqlite::Tools::executeRequest( dbConnection, indexAlbumIdReq );
sqlite::Tools::executeRequest( dbConnection,
index( Indexes::MediaArtistGenreAlbum, Settings::DbModelVersion ) );
sqlite::Tools::executeRequest( dbConnection,
index( Indexes::AlbumGenreArtist, Settings::DbModelVersion ) );
}
std::string AlbumTrack::schema( const std::string& tableName, uint32_t )
......@@ -126,11 +122,48 @@ std::string AlbumTrack::schema( const std::string& tableName, uint32_t )
")";
}
std::string AlbumTrack::index( AlbumTrack::Indexes index, uint32_t dbModel )
{
switch ( index )
{
case Indexes::AlbumGenreArtist:
return "CREATE INDEX " + indexName( index, dbModel ) +
" ON " + Table::Name +
"(album_id, genre_id, artist_id)";
case Indexes::MediaArtistGenreAlbum:
return "CREATE INDEX " + indexName( index, dbModel ) +
" ON " + Table::Name +
"(media_id, artist_id, genre_id, album_id)";
}
return "<invalid request>";
}
std::string AlbumTrack::indexName(AlbumTrack::Indexes index, uint32_t )
{
switch ( index )
{
case Indexes::AlbumGenreArtist:
return "album_track_album_genre_artist_ids";
case Indexes::MediaArtistGenreAlbum:
return "album_media_artist_genre_album_idx";
default:
assert( !"Invalid index provided" );
};
return "<invalid request>";
}
bool AlbumTrack::checkDbModel(MediaLibraryPtr ml)
{
return sqlite::Tools::checkSchema( ml->getConn(),
return sqlite::Tools::checkTableSchema( ml->getConn(),
schema( Table::Name, Settings::DbModelVersion ),
Table::Name );
Table::Name ) &&
sqlite::Tools::checkIndexStatement( ml->getConn(),
index( AlbumTrack::Indexes::AlbumGenreArtist, Settings::DbModelVersion ),
indexName( AlbumTrack::Indexes::AlbumGenreArtist, Settings::DbModelVersion ) ) &&
sqlite::Tools::checkIndexStatement( ml->getConn(),
index( AlbumTrack::Indexes::MediaArtistGenreAlbum, Settings::DbModelVersion ),
indexName( AlbumTrack::Indexes::MediaArtistGenreAlbum, Settings::DbModelVersion ) );
}
std::shared_ptr<AlbumTrack> AlbumTrack::create( MediaLibraryPtr ml, int64_t albumId,
......
......@@ -48,6 +48,12 @@ class AlbumTrack : public IAlbumTrack, public DatabaseHelpers<AlbumTrack>
static const std::string PrimaryKeyColumn;
static int64_t AlbumTrack::*const PrimaryKey;
};
enum class Indexes : uint8_t
{
MediaArtistGenreAlbum,
AlbumGenreArtist,
};
AlbumTrack( MediaLibraryPtr ml, sqlite::Row& row );
AlbumTrack( MediaLibraryPtr ml, int64_t mediaId, int64_t artistId, int64_t genreId,
unsigned int trackNumber, int64_t albumId, unsigned int discNumber );
......@@ -63,8 +69,10 @@ class AlbumTrack : public IAlbumTrack, public DatabaseHelpers<AlbumTrack>
virtual int64_t albumId() const override;
static void createTable( sqlite::Connection* dbConnection );
static void createTriggers( sqlite::Connection* dbConnection );
static void createIndexes( sqlite::Connection* dbConnection );
static std::string schema( const std::string& tableName, uint32_t dbModel );
static std::string index( Indexes index, uint32_t dbModel );
static std::string indexName( Indexes index, uint32_t dbModel );
static bool checkDbModel( MediaLibraryPtr ml );
static std::shared_ptr<AlbumTrack> create(MediaLibraryPtr ml, int64_t albumId,
int64_t mediaId, unsigned int trackNb,
......
......@@ -314,159 +314,34 @@ void Artist::createTable( sqlite::Connection* dbConnection )
void Artist::createTriggers( sqlite::Connection* dbConnection, uint32_t dbModelVersion )
{
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::HasTrackPresent, dbModelVersion ) );
if ( dbModelVersion < 23 )
{
static const std::string triggerReq = "CREATE TRIGGER IF NOT EXISTS has_tracks_present AFTER UPDATE OF "
"is_present ON " + Media::Table::Name +
" WHEN new.subtype = " +
std::to_string( static_cast<typename std::underlying_type<IMedia::SubType>::type>(
IMedia::SubType::AlbumTrack ) ) +
" BEGIN "
" UPDATE " + Table::Name + " SET is_present=is_present + "
"(CASE new.is_present WHEN 0 THEN -1 ELSE 1 END)"
"WHERE id_artist = (SELECT artist_id FROM " + AlbumTrack::Table::Name + " "
" WHERE media_id = new.id_media "
");"
" END";
sqlite::Tools::executeRequest( dbConnection, triggerReq );
// Automatically delete the artists that don't have any albums left, except the 2 special artists.
// Those are assumed to always exist, and deleting them would cause a constaint violation error
// when inserting an album with unknown/various artist(s).
// The alternative would be to always check the special artists for existence, which would be much
// slower when inserting an unknown artist album
static const std::string autoDeleteAlbumTriggerReq = "CREATE TRIGGER IF NOT EXISTS has_album_remaining"
" AFTER DELETE ON " + Album::Table::Name +
" WHEN old.artist_id != " + std::to_string( UnknownArtistID ) +
" AND old.artist_id != " + std::to_string( VariousArtistID ) +
" BEGIN"
" UPDATE " + Artist::Table::Name + " SET nb_albums = nb_albums - 1 WHERE id_artist = old.artist_id;"
" DELETE FROM " + Artist::Table::Name + " WHERE id_artist = old.artist_id "
" AND nb_albums = 0 "
" AND nb_tracks = 0;"
" END";
sqlite::Tools::executeRequest( dbConnection, autoDeleteAlbumTriggerReq );
}
if ( dbModelVersion >= 23 )
{
static const std::string triggerReq = "CREATE TRIGGER IF NOT EXISTS"
" artist_has_tracks_present AFTER UPDATE OF"
" is_present ON " + Media::Table::Name +
" WHEN new.subtype = " +
std::to_string( static_cast<typename std::underlying_type<IMedia::SubType>::type>(
IMedia::SubType::AlbumTrack ) ) +
" AND old.is_present != new.is_present"
" BEGIN "
" UPDATE " + Table::Name + " SET is_present=is_present + "
"(CASE new.is_present WHEN 0 THEN -1 ELSE 1 END)"
"WHERE id_artist = (SELECT artist_id FROM " + AlbumTrack::Table::Name + " "
" WHERE media_id = new.id_media "
");"
" END";
sqlite::Tools::executeRequest( dbConnection, triggerReq );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::HasAlbumRemaining, dbModelVersion ) );
}
static const std::string ftsInsertTrigger = "CREATE TRIGGER IF NOT EXISTS insert_artist_fts"
" AFTER INSERT ON " + Artist::Table::Name +
" WHEN new.name IS NOT NULL"
" BEGIN"
" INSERT INTO " + Artist::FtsTable::Name + "(rowid,name) VALUES(new.id_artist, new.name);"
" END";
static const std::string ftsDeleteTrigger = "CREATE TRIGGER IF NOT EXISTS delete_artist_fts"
" BEFORE DELETE ON " + Artist::Table::Name +
" WHEN old.name IS NOT NULL"
" BEGIN"
" DELETE FROM " + Artist::FtsTable::Name + " WHERE rowid=old.id_artist;"
" END";
// Don't create this trigger if the database is about to be migrated.
// This could make earlier migration fail, and needs to be done when
// migrating to v7 to v8.
// While the has_album_remaining trigger now also references the nb_tracks
// field, it was present from before version 3, so it wouldn't be recreated.
// As we don't support any model before 3 (or rather we just recreate
// everything), we don't have to bother here.
if ( dbModelVersion >= 8 && dbModelVersion < 23 )
{
static const std::string autoDeleteTrackTriggerReq = "CREATE TRIGGER IF NOT EXISTS has_track_remaining"
" AFTER DELETE ON " + AlbumTrack::Table::Name +
" WHEN old.artist_id != " + std::to_string( UnknownArtistID ) +
" AND old.artist_id != " + std::to_string( VariousArtistID ) +
" BEGIN"
" UPDATE " + Artist::Table::Name + " SET"
" nb_tracks = nb_tracks - 1,"
" is_present = is_present - 1"
" WHERE id_artist = old.artist_id;"
" DELETE FROM " + Artist::Table::Name + " WHERE id_artist = old.artist_id "
" AND nb_albums = 0 "
" AND nb_tracks = 0;"
" END";
sqlite::Tools::executeRequest( dbConnection, autoDeleteTrackTriggerReq );
}
else
{
static const std::string autoDeleteArtistWithoutTracks =
"CREATE TRIGGER IF NOT EXISTS delete_artist_without_tracks"
" AFTER UPDATE OF nb_tracks, nb_albums ON " + Table::Name +
" WHEN new.nb_tracks = 0 AND new.nb_albums = 0"
" AND new.id_artist != " + std::to_string( UnknownArtistID ) +
" AND new.id_artist != " + std::to_string( VariousArtistID ) +
" BEGIN"
" DELETE FROM " + Table::Name + " WHERE id_artist = old.id_artist;"
" END";
sqlite::Tools::executeRequest( dbConnection, autoDeleteArtistWithoutTracks );
}
sqlite::Tools::executeRequest( dbConnection, ftsInsertTrigger );
sqlite::Tools::executeRequest( dbConnection, ftsDeleteTrigger );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::InsertFts, dbModelVersion ) );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::DeleteFts, dbModelVersion ) );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::DeleteArtistsWithoutTracks, dbModelVersion ) );
if ( dbModelVersion >= 23 )
{
static const std::string incrementNbTracksTrigger = "CREATE TRIGGER IF NOT EXISTS"
" artist_increment_nb_tracks"
" AFTER INSERT ON " + MediaRelationTable::Name +
" BEGIN"
" UPDATE " + Table::Name +
" SET nb_tracks = nb_tracks + 1, is_present = is_present + 1"
" WHERE id_artist = new.artist_id;"
" END";
static const std::string decrementNbTracksTrigger = "CREATE TRIGGER IF NOT EXISTS"
" artist_decrement_nb_tracks"
" AFTER DELETE ON " + MediaRelationTable::Name +
" BEGIN"
" UPDATE " + Table::Name +
" SET nb_tracks = nb_tracks - 1, is_present = is_present - 1"
" WHERE id_artist = old.artist_id;"
" END";
static const std::string updateNbAlbumTrigger = "CREATE TRIGGER IF NOT EXISTS"
" artist_update_nb_albums"
" AFTER UPDATE OF artist_id ON " + Album::Table::Name +
" BEGIN"
" UPDATE " + Table::Name + " SET nb_albums = nb_albums + 1"
" WHERE id_artist = new.artist_id;"
// Even if this is the first update, the old value will be NULL
// and won't update anything
" UPDATE " + Table::Name + " SET nb_albums = nb_albums - 1"
" WHERE id_artist = old.artist_id;"
" END";
static const std::string decrementNbAlbumTrigger = "CREATE TRIGGER IF NOT EXISTS"
" artist_decrement_nb_albums"
" AFTER DELETE ON " + Album::Table::Name +
" BEGIN"
" UPDATE " + Table::Name + " SET nb_albums = nb_albums - 1"
" WHERE id_artist = old.artist_id;"
" END";
static const std::string updateNbAlbumUnknown = "CREATE TRIGGER IF NOT EXISTS"
" artist_increment_nb_albums_unknown_album"
" AFTER INSERT ON " + Album::Table::Name +
" WHEN new.artist_id IS NOT NULL"
" BEGIN"
" UPDATE " + Table::Name + " SET nb_albums = nb_albums + 1"
" WHERE id_artist = new.artist_id;"
" END";
sqlite::Tools::executeRequest( dbConnection, incrementNbTracksTrigger );
sqlite::Tools::executeRequest( dbConnection, decrementNbTracksTrigger );
sqlite::Tools::executeRequest( dbConnection, updateNbAlbumTrigger );
sqlite::Tools::executeRequest( dbConnection, decrementNbAlbumTrigger );
sqlite::Tools::executeRequest( dbConnection, updateNbAlbumUnknown );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::IncrementNbTracks, dbModelVersion ) );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::DecrementNbTracks, dbModelVersion ) );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::UpdateNbAlbums, dbModelVersion ) );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::DecrementNbAlbums, dbModelVersion ) );
sqlite::Tools::executeRequest( dbConnection,
trigger( Triggers::IncrementNbAlbums, dbModelVersion ) );
}