Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Jian Li
medialibrary
Commits
f13fb525
Commit
f13fb525
authored
Dec 20, 2019
by
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
Changes
66
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Makefile.am
View file @
f13fb525
...
...
@@ -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)
...
...
include/medialibrary/IMediaLibrary.h
View file @
f13fb525
...
...
@@ -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
;
...
...
src/Album.cpp
View file @
f13fb525
...
...
@@ -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
::
check
Table
Schema
(
ml
->
getConn
(),
schema
(
Table
::
Name
,
Settings
::
DbModelVersion
),
Table
::
Name
)
&&
sqlite
::
Tools
::
checkSchema
(
ml
->
getConn
(),
Table
::
Name
)
==
false
||
sqlite
::
Tools
::
check
Table
Schema
(
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
)
...
...
src/Album.h
View file @
f13fb525
...
...
@@ -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
);
...
...
src/AlbumTrack.cpp
View file @
f13fb525
...
...
@@ -91,16 +91,12 @@ void AlbumTrack::createTable( sqlite::Connection* dbConnection )
Settings
::
DbModelVersion
)
);
}
void
AlbumTrack
::
create
Trigger
s
(
sqlite
::
Connection
*
dbConnection
)
void
AlbumTrack
::
create
Indexe
s
(
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
::
check
Table
Schema
(
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
,
...
...
src/AlbumTrack.h
View file @
f13fb525
...
...
@@ -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
create
Trigger
s
(
sqlite
::
Connection
*
dbConnection
);
static
void
create
Indexe
s
(
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
,
...
...
src/Artist.cpp
View file @
f13fb525
...
...
@@ -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
)
);
}