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

Folder: Add a nb_media field

ref #42
parent 861d977f
...@@ -47,6 +47,7 @@ public: ...@@ -47,6 +47,7 @@ public:
* from being discovered. * from being discovered.
*/ */
virtual bool isBanned() const = 0; virtual bool isBanned() const = 0;
virtual uint32_t nbMedia() const = 0;
}; };
} }
...@@ -52,6 +52,7 @@ Folder::Folder( MediaLibraryPtr ml, sqlite::Row& row ) ...@@ -52,6 +52,7 @@ Folder::Folder( MediaLibraryPtr ml, sqlite::Row& row )
, m_isBanned( row.load<decltype(m_isBanned)>( 3 ) ) , m_isBanned( row.load<decltype(m_isBanned)>( 3 ) )
, m_deviceId( row.load<decltype(m_deviceId)>( 4 ) ) , m_deviceId( row.load<decltype(m_deviceId)>( 4 ) )
, m_isRemovable( row.load<decltype(m_isRemovable)>( 5 ) ) , m_isRemovable( row.load<decltype(m_isRemovable)>( 5 ) )
, m_nbMedia( row.load<decltype(m_nbMedia)>( 6 ) )
{ {
} }
...@@ -75,13 +76,35 @@ void Folder::createTable( sqlite::Connection* connection) ...@@ -75,13 +76,35 @@ void Folder::createTable( sqlite::Connection* connection)
sqlite::Tools::executeRequest( connection, req ); sqlite::Tools::executeRequest( connection, req );
} }
void Folder::createTriggers( sqlite::Connection* connection ) void Folder::createTriggers( sqlite::Connection* connection, uint32_t modelVersion )
{ {
const std::string reqs[] = { const std::string reqs[] = {
#include "database/tables/Folder_triggers_v14.sql" #include "database/tables/Folder_triggers_v14.sql"
}; };
for ( const auto& req : reqs ) for ( const auto& req : reqs )
sqlite::Tools::executeRequest( connection, req ); sqlite::Tools::executeRequest( connection, req );
if ( modelVersion >= 14 )
{
const std::string v14Reqs[] = {
"CREATE TRIGGER IF NOT EXISTS update_folder_nb_media_on_insert "
"AFTER INSERT ON " + Media::Table::Name + " "
"WHEN new.folder_id IS NOT NULL "
"BEGIN "
"UPDATE " + Folder::Table::Name + " SET nb_media = nb_media + 1 "
"WHERE id_folder = new.folder_id;"
"END",
"CREATE TRIGGER IF NOT EXISTS update_folder_nb_media_on_delete "
"AFTER DELETE ON " + Media::Table::Name + " "
"WHEN old.folder_id IS NOT NULL "
"BEGIN "
"UPDATE " + Folder::Table::Name + " SET nb_media = nb_media - 1 "
"WHERE id_folder = old.folder_id;"
"END",
};
for ( const auto& req : v14Reqs )
sqlite::Tools::executeRequest( connection, req );
}
} }
std::shared_ptr<Folder> Folder::create( MediaLibraryPtr ml, const std::string& mrl, std::shared_ptr<Folder> Folder::create( MediaLibraryPtr ml, const std::string& mrl,
...@@ -334,6 +357,11 @@ bool Folder::isRootFolder() const ...@@ -334,6 +357,11 @@ bool Folder::isRootFolder() const
return m_parent == 0; return m_parent == 0;
} }
uint32_t Folder::nbMedia() const
{
return m_nbMedia;
}
std::vector<std::shared_ptr<Folder>> Folder::fetchRootFolders( MediaLibraryPtr ml ) std::vector<std::shared_ptr<Folder>> Folder::fetchRootFolders( MediaLibraryPtr ml )
{ {
static const std::string req = "SELECT * FROM " + Folder::Table::Name + " f " static const std::string req = "SELECT * FROM " + Folder::Table::Name + " f "
......
...@@ -56,7 +56,7 @@ public: ...@@ -56,7 +56,7 @@ public:
Folder(MediaLibraryPtr ml, const std::string& path, int64_t parent , int64_t deviceId , bool isRemovable ); Folder(MediaLibraryPtr ml, const std::string& path, int64_t parent , int64_t deviceId , bool isRemovable );
static void createTable( sqlite::Connection* connection ); static void createTable( sqlite::Connection* connection );
static void createTriggers( sqlite::Connection* connection ); static void createTriggers( sqlite::Connection* connection, uint32_t modelVersion );
static std::shared_ptr<Folder> create( MediaLibraryPtr ml, const std::string& mrl, int64_t parentId, Device& device, fs::IDevice& deviceFs ); static std::shared_ptr<Folder> create( MediaLibraryPtr ml, const std::string& mrl, int64_t parentId, Device& device, fs::IDevice& deviceFs );
static void excludeEntryFolder( MediaLibraryPtr ml, int64_t folderId ); static void excludeEntryFolder( MediaLibraryPtr ml, int64_t folderId );
static bool ban( MediaLibraryPtr ml, const std::string& mrl ); static bool ban( MediaLibraryPtr ml, const std::string& mrl );
...@@ -76,6 +76,7 @@ public: ...@@ -76,6 +76,7 @@ public:
virtual bool isPresent() const override; virtual bool isPresent() const override;
virtual bool isBanned() const override; virtual bool isBanned() const override;
bool isRootFolder() const; bool isRootFolder() const;
virtual uint32_t nbMedia() const override;
enum class BannedType enum class BannedType
{ {
...@@ -97,6 +98,7 @@ private: ...@@ -97,6 +98,7 @@ private:
const bool m_isBanned; const bool m_isBanned;
const int64_t m_deviceId; const int64_t m_deviceId;
const bool m_isRemovable; const bool m_isRemovable;
uint32_t m_nbMedia;
mutable std::string m_deviceMountpoint; mutable std::string m_deviceMountpoint;
mutable std::shared_ptr<Device> m_device; mutable std::shared_ptr<Device> m_device;
......
...@@ -157,7 +157,7 @@ void MediaLibrary::createAllTables() ...@@ -157,7 +157,7 @@ void MediaLibrary::createAllTables()
void MediaLibrary::createAllTriggers() void MediaLibrary::createAllTriggers()
{ {
auto dbModelVersion = m_settings.dbModelVersion(); auto dbModelVersion = m_settings.dbModelVersion();
Folder::createTriggers( m_dbConnection.get() ); Folder::createTriggers( m_dbConnection.get(), dbModelVersion );
Album::createTriggers( m_dbConnection.get() ); Album::createTriggers( m_dbConnection.get() );
AlbumTrack::createTriggers( m_dbConnection.get() ); AlbumTrack::createTriggers( m_dbConnection.get() );
Artist::createTriggers( m_dbConnection.get(), dbModelVersion ); Artist::createTriggers( m_dbConnection.get(), dbModelVersion );
...@@ -1178,7 +1178,7 @@ void MediaLibrary::migrateModel13to14( uint32_t originalPreviousVersion ) ...@@ -1178,7 +1178,7 @@ void MediaLibrary::migrateModel13to14( uint32_t originalPreviousVersion )
Artist::createTriggers( dbConn, 14 ); Artist::createTriggers( dbConn, 14 );
Show::createTriggers( dbConn ); Show::createTriggers( dbConn );
Playlist::createTriggers( dbConn ); Playlist::createTriggers( dbConn );
Folder::createTriggers( dbConn ); Folder::createTriggers( dbConn, 14 );
const std::string req = "SELECT * FROM " + Media::Table::Name + const std::string req = "SELECT * FROM " + Media::Table::Name +
" WHERE filename LIKE '%#%%' ESCAPE '#'"; " WHERE filename LIKE '%#%%' ESCAPE '#'";
auto media = Media::fetchAll<Media>( this, req ); auto media = Media::fetchAll<Media>( this, req );
......
...@@ -173,6 +173,9 @@ IMedia::Type::Unknown ) ), ...@@ -173,6 +173,9 @@ IMedia::Type::Unknown ) ),
"SELECT id_folder, path, parent_id, is_blacklisted, device_id, is_removable " "SELECT id_folder, path, parent_id, is_blacklisted, device_id, is_removable "
"FROM " + Folder::Table::Name + "_backup", "FROM " + Folder::Table::Name + "_backup",
"UPDATE " + Folder::Table::Name + " SET nb_media = "
"(SELECT COUNT() FROM " + Media::Table::Name + " m WHERE m.folder_id = id_folder )",
"DROP TABLE " + Folder::Table::Name + "_backup", "DROP TABLE " + Folder::Table::Name + "_backup",
/******************* Migrate File table *************************************/ /******************* Migrate File table *************************************/
......
...@@ -2,4 +2,5 @@ ...@@ -2,4 +2,5 @@
Folder::Table::Name + " (device_id)", Folder::Table::Name + " (device_id)",
"CREATE INDEX IF NOT EXISTS parent_folder_id_idx ON " + "CREATE INDEX IF NOT EXISTS parent_folder_id_idx ON " +
Folder::Table::Name + " (parent_id)" Folder::Table::Name + " (parent_id)",
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
"is_banned BOOLEAN NOT NULL DEFAULT 0," "is_banned BOOLEAN NOT NULL DEFAULT 0,"
"device_id UNSIGNED INTEGER," "device_id UNSIGNED INTEGER,"
"is_removable BOOLEAN NOT NULL," "is_removable BOOLEAN NOT NULL,"
"nb_media UNSIGNED INTEGER NOT NULL DEFAULT 0,"
"FOREIGN KEY (parent_id) REFERENCES " + Folder::Table::Name + "FOREIGN KEY (parent_id) REFERENCES " + Folder::Table::Name +
"(id_folder) ON DELETE CASCADE," "(id_folder) ON DELETE CASCADE,"
......
...@@ -54,6 +54,11 @@ FolderPtr MediaLibraryTester::folder( const std::string& mrl ) const ...@@ -54,6 +54,11 @@ FolderPtr MediaLibraryTester::folder( const std::string& mrl ) const
return Folder::fromMrl( this, mrl, Folder::BannedType::No ); return Folder::fromMrl( this, mrl, Folder::BannedType::No );
} }
FolderPtr MediaLibraryTester::folder(int64_t id) const
{
return Folder::fetch( this, id );
}
std::shared_ptr<Media> MediaLibraryTester::addFile( const std::string& path, IMedia::Type type ) std::shared_ptr<Media> MediaLibraryTester::addFile( const std::string& path, IMedia::Type type )
{ {
return addFile( std::make_shared<mock::NoopFile>( path ), return addFile( std::make_shared<mock::NoopFile>( path ),
......
...@@ -47,6 +47,7 @@ public: ...@@ -47,6 +47,7 @@ public:
// And override the ID getter to return a Media instead of IMedia // And override the ID getter to return a Media instead of IMedia
std::shared_ptr<Media> media( int64_t id ); std::shared_ptr<Media> media( int64_t id );
FolderPtr folder( const std::string& path ) const override; FolderPtr folder( const std::string& path ) const override;
FolderPtr folder( int64_t id ) const;
void deleteAlbum( int64_t albumId ); void deleteAlbum( int64_t albumId );
std::shared_ptr<Album> createAlbum( const std::string& title ); std::shared_ptr<Album> createAlbum( const std::string& title );
std::shared_ptr<Genre> createGenre( const std::string& name ); std::shared_ptr<Genre> createGenre( const std::string& name );
......
...@@ -452,3 +452,24 @@ TEST_F( Folders, RemoveRootFolder ) ...@@ -452,3 +452,24 @@ TEST_F( Folders, RemoveRootFolder )
ASSERT_EQ( 0u, ml->files().size() ); ASSERT_EQ( 0u, ml->files().size() );
} }
TEST_F( Folders, NbMedia )
{
auto root = ml->folder( 1 );
auto subFolder = ml->folder( 2 );
ASSERT_EQ( "file:///a/", root->mrl() );
ASSERT_EQ( "file:///a/folder/", subFolder->mrl() );
ASSERT_EQ( 2u, root->nbMedia() );
ASSERT_EQ( 1u, subFolder->nbMedia() );
// Do not watch for live changes
ml.reset();
fsMock->removeFile( mock::FileSystemFactory::SubFolder + "subfile.mp4" );
Reload();
root = ml->folder( 1 );
subFolder = ml->folder( 2 );
ASSERT_EQ( 2u, root->nbMedia() );
ASSERT_EQ( 0u, subFolder->nbMedia() );
}
...@@ -174,7 +174,7 @@ TEST_F( DbModel, Upgrade12to13 ) ...@@ -174,7 +174,7 @@ TEST_F( DbModel, Upgrade12to13 )
// We can't check for the number of albums anymore since they are deleted // We can't check for the number of albums anymore since they are deleted
// as part of 13 -> 14 migration // as part of 13 -> 14 migration
CheckNbTriggers( 30 ); CheckNbTriggers( 32 );
} }
TEST_F( DbModel, Upgrade13to14 ) TEST_F( DbModel, Upgrade13to14 )
...@@ -216,6 +216,9 @@ TEST_F( DbModel, Upgrade13to14 ) ...@@ -216,6 +216,9 @@ TEST_F( DbModel, Upgrade13to14 )
ASSERT_EQ( IMedia::Type::Unknown, externalMedia->type() ); ASSERT_EQ( IMedia::Type::Unknown, externalMedia->type() );
ASSERT_EQ( 0u, std::static_pointer_cast<Media>( externalMedia )->nbPlaylists() ); ASSERT_EQ( 0u, std::static_pointer_cast<Media>( externalMedia )->nbPlaylists() );
auto folder = ml->folder( 1 );
ASSERT_NE( nullptr, folder );
ASSERT_EQ( 2u, folder->nbMedia() );
CheckNbTriggers( 30 ); CheckNbTriggers( 32 );
} }
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