Commit 26cbf3dd authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

MediaGroup: Update per-type media count based on media presence

fix #251
parent 1fb13b82
Pipeline #17251 passed with stage
in 3 minutes and 51 seconds
......@@ -437,6 +437,8 @@ void MediaGroup::createTriggers( sqlite::Connection* connection )
trigger( Triggers::UpdateDurationOnMediaDeletion, Settings::DbModelVersion ) );
sqlite::Tools::executeRequest( connection,
trigger( Triggers::UpdateTotalNbMedia, Settings::DbModelVersion ) );
sqlite::Tools::executeRequest( connection,
trigger( Triggers::UpdateMediaCountOnPresenceChange, Settings::DbModelVersion ) );
}
void MediaGroup::createIndexes( sqlite::Connection* connection )
......@@ -723,6 +725,40 @@ std::string MediaGroup::trigger( MediaGroup::Triggers t, uint32_t dbModel )
" WHERE new.group_id IS NOT NULL AND id_group = new.group_id;"
" END";
}
case Triggers::UpdateMediaCountOnPresenceChange:
{
assert( dbModel >= 26 );
return "CREATE TRIGGER " + triggerName( t, dbModel ) +
" AFTER UPDATE OF is_present ON " + Media::Table::Name +
" WHEN old.is_present != new.is_present"
" AND new.group_id IS NOT NULL"
" BEGIN"
" UPDATE " + Table::Name + " SET"
/* Compute the increment in 2 steps: first set it to 1 if the
* media type matches the targeted field, then negate it if
* the media went missing
*/
" nb_video = nb_video + "
" (CASE new.type WHEN " +
std::to_string( static_cast<std::underlying_type_t<IMedia::Type>>(
IMedia::Type::Video ) ) +
" THEN 1 ELSE 0 END) *"
" (CASE new.is_present WHEN 0 THEN -1 ELSE 1 END),"
" nb_audio = nb_audio + "
" (CASE new.type WHEN " +
std::to_string( static_cast<std::underlying_type_t<IMedia::Type>>(
IMedia::Type::Audio ) ) +
" THEN 1 ELSE 0 END) *"
" (CASE new.is_present WHEN 0 THEN -1 ELSE 1 END),"
" nb_unknown = nb_unknown + "
" (CASE new.type WHEN " +
std::to_string( static_cast<std::underlying_type_t<IMedia::Type>>(
IMedia::Type::Unknown ) ) +
" THEN 1 ELSE 0 END) *"
" (CASE new.is_present WHEN 0 THEN -1 ELSE 1 END)"
" WHERE id_group = new.group_id;"
" END";
}
default:
assert( !"Invalid trigger" );
}
......@@ -764,6 +800,9 @@ std::string MediaGroup::triggerName(MediaGroup::Triggers t, uint32_t dbModel)
case Triggers::UpdateTotalNbMedia:
assert( dbModel >= 26 );
return "media_group_update_total_nb_media";
case Triggers::UpdateMediaCountOnPresenceChange:
assert( dbModel >= 26 );
return "media_group_update_nb_media_types_presence";
default:
assert( !"Invalid trigger" );
}
......
......@@ -57,6 +57,7 @@ public:
UpdateDurationOnMediaDeletion,
UpdateNbMediaPerType,
UpdateTotalNbMedia,
UpdateMediaCountOnPresenceChange,
};
enum class Indexes : uint8_t
{
......
......@@ -52,8 +52,17 @@ Show::trigger( Show::Triggers::DeleteFts, 26 ),
MediaGroup::schema( MediaGroup::Table::Name, 26 ),
#define COUNT_MEDIA(type) \
" (SELECT COUNT(*) FROM " + Media::Table::Name + " m" \
" WHERE m.group_id = mg.id_group AND m.is_present != 0 AND " \
" m.type = " + std::to_string( \
static_cast<std::underlying_type_t<IMedia::Type>>( type ) ) + "), "
"INSERT INTO " + MediaGroup::Table::Name +
" SELECT id_group, name, nb_video, nb_audio, nb_unknown, "
" SELECT id_group, name,"
COUNT_MEDIA(IMedia::Type::Video)
COUNT_MEDIA(IMedia::Type::Audio)
COUNT_MEDIA(IMedia::Type::Unknown)
"(SELECT COUNT(*) FROM " + Media::Table::Name + " m WHERE m.group_id = mg.id_group), "
"duration, creation_date, last_modification_date, user_interacted, forced_singleton "
" FROM " + MediaGroup::Table::Name + "_backup mg",
......@@ -68,8 +77,9 @@ MediaGroup::trigger( MediaGroup::Triggers::UpdateNbMediaPerType, 26 ),
"DROP TRIGGER " + MediaGroup::triggerName( MediaGroup::Triggers::DecrementNbMediaOnDeletion, 25 ),
MediaGroup::trigger( MediaGroup::Triggers::DecrementNbMediaOnDeletion, 26 ),
/* Create new MediaGroup trigger */
/* Create new MediaGroup triggers */
MediaGroup::trigger( MediaGroup::Triggers::UpdateTotalNbMedia, 26 ),
MediaGroup::trigger( MediaGroup::Triggers::UpdateMediaCountOnPresenceChange, 26 ),
/* Recreate MediaGroup indexes & triggers that were deleted during the migration */
MediaGroup::trigger( MediaGroup::Triggers::InsertFts, 26 ),
......
......@@ -32,6 +32,8 @@
#include "Media.h"
#include "Artist.h"
#include "Show.h"
#include "MediaGroup.h"
#include "mocks/FileSystem.h"
#include "mocks/DiscovererCbMock.h"
......@@ -78,6 +80,54 @@ protected:
auto res = cbMock->waitReload();
ASSERT_TRUE( res );
}
void enforceFakeMediaTypes()
{
auto media = std::static_pointer_cast<Media>( ml->media(
mock::FileSystemFactory::Root + "video.avi" ) );
media->setType( IMedia::Type::Video );
media->save();
media = std::static_pointer_cast<Media>( ml->media(
mock::FileSystemFactory::Root + "audio.mp3" ) );
media->setType( IMedia::Type::Audio );
media->save();
media = std::static_pointer_cast<Media>( ml->media(
mock::FileSystemFactory::SubFolder + "subfile.mp4" ) );
media->setType( IMedia::Type::Video );
media->save();
media = std::static_pointer_cast<Media>( ml->media(
RemovableDeviceMountpoint + "removablefile.mp3" ) );
media->setType( IMedia::Type::Audio );
media->save();
media = std::static_pointer_cast<Media>( ml->media(
RemovableDeviceMountpoint + "removablefile2.mp3" ) );
media->setType( IMedia::Type::Audio );
media->save();
media = std::static_pointer_cast<Media>( ml->media(
RemovableDeviceMountpoint + "removablefile3.mp3" ) );
media->setType( IMedia::Type::Audio );
media->save();
media = std::static_pointer_cast<Media>( ml->media(
RemovableDeviceMountpoint + "removablefile4.mp3" ) );
media->setType( IMedia::Type::Audio );
media->save();
media = std::static_pointer_cast<Media>( ml->media(
RemovableDeviceMountpoint + "removablevideo.mkv" ) );
media->setType( IMedia::Type::Video );
media->save();
media = std::static_pointer_cast<Media>( ml->media(
RemovableDeviceMountpoint + "removablevideo2.mkv" ) );
media->setType( IMedia::Type::Video );
media->save();
}
};
const std::string DeviceFs::RemovableDeviceUuid = "{fake-removable-device}";
......@@ -635,3 +685,70 @@ TEST_F( DeviceFs, PartialRemoveShowEpisodes )
ASSERT_EQ( 2u, episodeQuery->count() );
ASSERT_EQ( 2u, episodeQuery->all().size() );
}
TEST_F( DeviceFs, MediaGroupPresence )
{
ml->discover( mock::FileSystemFactory::Root );
bool discovered = cbMock->waitDiscovery();
ASSERT_TRUE( discovered );
enforceFakeMediaTypes();
auto addToGroup = [this]( IMediaGroup& mg, const std::string& mrl ) {
auto m = ml->media( mrl );
ASSERT_NE( nullptr, m );
auto res = mg.add( *m );
ASSERT_TRUE( res );
};
auto rmg = ml->createMediaGroup( "removable group" );
addToGroup( *rmg, RemovableDeviceMountpoint + "removablefile.mp3" );
addToGroup( *rmg, RemovableDeviceMountpoint + "removablefile2.mp3" );
addToGroup( *rmg, RemovableDeviceMountpoint + "removablefile3.mp3" );
addToGroup( *rmg, RemovableDeviceMountpoint + "removablefile4.mp3" );
addToGroup( *rmg, RemovableDeviceMountpoint + "removablevideo.mkv" );
addToGroup( *rmg, RemovableDeviceMountpoint + "removablevideo2.mkv" );
ASSERT_EQ( 4u, rmg->nbAudio() );
ASSERT_EQ( 2u, rmg->nbVideo() );
ASSERT_EQ( 0u, rmg->nbUnknown() );
ASSERT_EQ( 6u, rmg->nbMedia() );
auto groups = ml->mediaGroups( nullptr )->all();
ASSERT_EQ( 1u, groups.size() );
rmg = ml->mediaGroup( rmg->id() );
ASSERT_EQ( 4u, rmg->nbAudio() );
ASSERT_EQ( 2u, rmg->nbVideo() );
ASSERT_EQ( 0u, rmg->nbUnknown() );
ASSERT_EQ( 6u, rmg->nbMedia() );
ASSERT_EQ( 6u, rmg->nbTotalMedia() );
auto device = fsMock->removeDevice( RemovableDeviceUuid );
Reload();
rmg = ml->mediaGroup( rmg->id() );
ASSERT_EQ( 0u, rmg->nbAudio() );
ASSERT_EQ( 0u, rmg->nbVideo() );
ASSERT_EQ( 0u, rmg->nbUnknown() );
ASSERT_EQ( 0u, rmg->nbMedia() );
ASSERT_EQ( 6u, rmg->nbTotalMedia() );
groups = ml->mediaGroups( nullptr )->all();
ASSERT_EQ( 0u, groups.size() );
fsMock->addDevice( device );
Reload();
groups = ml->mediaGroups( nullptr )->all();
ASSERT_EQ( 1u, groups.size() );
rmg = ml->mediaGroup( rmg->id() );
ASSERT_EQ( 4u, rmg->nbAudio() );
ASSERT_EQ( 2u, rmg->nbVideo() );
ASSERT_EQ( 0u, rmg->nbUnknown() );
ASSERT_EQ( 6u, rmg->nbMedia() );
}
......@@ -75,6 +75,7 @@ namespace
"media_group_update_duration_on_media_change",
"media_group_update_duration_on_media_deletion",
"media_group_update_nb_media_types",
"media_group_update_nb_media_types_presence",
"media_group_update_total_nb_media",
"media_update_device_presence",
"show_decrement_nb_episode",
......@@ -673,4 +674,12 @@ TEST_F( DbModel, Upgrade25to26 )
row >> nbUnknownFileTypeRestoreTask;
}
ASSERT_EQ( 0u, nbUnknownFileTypeRestoreTask );
auto mg = ml->mediaGroup( 1 );
ASSERT_EQ( "test-group", mg->name() );
ASSERT_EQ( 1u, mg->nbAudio() );
ASSERT_EQ( 0u, mg->nbVideo() );
ASSERT_EQ( 0u, mg->nbUnknown() );
ASSERT_EQ( 1u, mg->nbMedia() );
ASSERT_EQ( 2u, mg->nbTotalMedia() );
}
......@@ -123,15 +123,20 @@ INSERT INTO Settings VALUES(25);
INSERT INTO Device VALUES(1,'720f7152-67b7-41da-89cf-bf22cef92095','file://',0,1,1,0);
INSERT INTO Device VALUES(2,'c276195d-2cd6-453f-ba04-5f179537e26e','file://',0,1,1,0);
INSERT INTO Device VALUES(3,'7dabfbff-2a61-424d-934c-2f7fa633e017','file://',0,1,1,0);
INSERT INTO Device VALUES(4,'fake-removable','file://',1,0,0,0);
INSERT INTO Folder VALUES(1,'file:///home/chouquette/dev/medialibrary/test/samples/samples/music/compilation/','compilation',NULL,0,1,0,4,0);
INSERT INTO Folder VALUES(2,'','removable-root',NULL,0,4,1,1,0);
INSERT INTO MediaGroup VALUES(1, 'test-group', 0, 2, 0, 0, 0, 0, 0, 0);
INSERT INTO Media VALUES(1,2,3,10057,NULL,NULL,NULL,1585305577,2015,'Track 1','track.mp3',0,1,1,0,1,0,NULL,0);
INSERT INTO Media VALUES(2,2,3,10057,NULL,NULL,NULL,1585305577,2011,'Track 2','track2.mp3',0,1,1,0,1,0,NULL,0);
INSERT INTO Media VALUES(3,2,3,10057,NULL,NULL,NULL,1585305577,0,'Track 3','track3.mp3',0,1,1,0,1,0,NULL,0);
INSERT INTO Media VALUES(4,2,3,10057,NULL,NULL,NULL,1585305577,2013,'Track 4','track4.mp3',0,1,1,0,1,0,NULL,0);
INSERT INTO Media VALUES(4,2,3,10057,NULL,NULL,NULL,1585305577,2013,'Track 4','track4.mp3',0,1,1,0,1,0,1,0);
INSERT INTO Media VALUES(5,2,3,10057,NULL,NULL,NULL,1585305577,2013,'Track 4','track4.mp3',0,0,4,0,1,0,1,0);
INSERT INTO File VALUES(1,1,NULL,'file:///home/chouquette/dev/medialibrary/test/samples/samples/music/compilation/track.mp3',1,1574114470,139264,1,0,0,0);
INSERT INTO File VALUES(2,2,NULL,'file:///home/chouquette/dev/medialibrary/test/samples/samples/music/compilation/track2.mp3',1,1574114470,139264,1,0,0,0);
INSERT INTO File VALUES(3,3,NULL,'file:///home/chouquette/dev/medialibrary/test/samples/samples/music/compilation/track3.mp3',1,1574114470,139264,1,0,0,0);
INSERT INTO File VALUES(4,4,NULL,'file:///home/chouquette/dev/medialibrary/test/samples/samples/music/compilation/track4.mp3',1,1574114470,139264,1,0,0,0);
INSERT INTO File VALUES(5,5,NULL,'removabletrack.mp3',1,1574114470,139264,2,1,0,0);
INSERT INTO Album VALUES(1,'Compilation',3,0,NULL,4,40228,1,4);
INSERT INTO AlbumTrack VALUES(1,1,10057,4,NULL,0,1,0);
INSERT INTO AlbumTrack VALUES(2,2,10057,5,NULL,0,1,0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment