diff --git a/include/database/AlbumRepository.h b/include/database/AlbumRepository.h index 3ccd37b..f831e02 100644 --- a/include/database/AlbumRepository.h +++ b/include/database/AlbumRepository.h @@ -1,6 +1,7 @@ #ifndef ALBUMREPOSITORY_H_ #define ALBUMREPOSITORY_H_ +#include #include #include "database/BaseRepository.h" @@ -16,14 +17,19 @@ namespace database std::vector retrieveRecords(); + std::pair retrieveRecordWithSongCount(model::Album&, type::AlbumFilter); + model::Album retrieveRecord(model::Album&, type::AlbumFilter); bool doesAlbumExists(const model::Album&, type::AlbumFilter); void saveAlbum(const model::Album&); + void deleteAlbum(const model::Album&, type::AlbumFilter); private: std::vector parseRecords(MYSQL_STMT*); + std::pair parseRecordWithSongCount(MYSQL_STMT*); + // TODO: after parseRecord(MYSQL_STMT*) is implemented remove // parseRecord(MYSQL_RES*) model::Album parseRecord(MYSQL_RES*); diff --git a/include/manager/AlbumManager.h b/include/manager/AlbumManager.h index f4794b7..f72dab9 100644 --- a/include/manager/AlbumManager.h +++ b/include/manager/AlbumManager.h @@ -13,6 +13,8 @@ namespace manager model::Album retrieveAlbum(model::Album&); model::Album saveAlbum(const model::Song&); + void deleteAlbum(const model::Song&); + static void printAlbum(const model::Album&); private: model::BinaryPath m_bConf; diff --git a/include/manager/CoverArtManager.h b/include/manager/CoverArtManager.h index 11434ec..f6527de 100644 --- a/include/manager/CoverArtManager.h +++ b/include/manager/CoverArtManager.h @@ -14,6 +14,8 @@ namespace manager CoverArtManager(const model::BinaryPath& bConf); model::Cover saveCover(const model::Song&, std::string&, const std::string&); + + void deleteCover(const model::Song&); private: model::BinaryPath m_bConf; std::string path; diff --git a/include/manager/SongManager.h b/include/manager/SongManager.h index a62fa1b..d4d0e0c 100644 --- a/include/manager/SongManager.h +++ b/include/manager/SongManager.h @@ -23,6 +23,7 @@ namespace manager private: void saveSongTemp(model::Song&); void saveMisc(model::Song&); + void deleteMisc(const model::Song&); model::BinaryPath m_bConf; std::string exe_path; diff --git a/include/model/Models.h b/include/model/Models.h index 50949ea..6c4194c 100644 --- a/include/model/Models.h +++ b/include/model/Models.h @@ -32,6 +32,11 @@ namespace model struct Artist { Artist() = default; + Artist(const Song& song) + { + id = song.artistId; + artist = song.artist; + } Artist(const int id) : id(id) { } int id; @@ -41,6 +46,12 @@ namespace model struct Album { Album() = default; + Album(const Song& song) + { + id = song.albumId; + title = song.album; + year = song.year; + } Album(const int id) : id(id) { } int id; @@ -52,6 +63,11 @@ namespace model struct Genre { Genre() = default; + Genre(const Song& song) + { + id = song.genreId; + category = song.genre; + } Genre(const int id) : id(id) { } int id; @@ -62,6 +78,11 @@ namespace model struct Year { Year() = default; + Year(const Song& song) + { + id = song.yearId; + year = song.year; + } Year(const int id) : id(id) { } int id; @@ -71,6 +92,11 @@ namespace model struct Cover { Cover() = default; + Cover(const Song& song) + { + id = song.coverArtId; + songTitle = song.title; + } Cover(const int id) : id(id) { } int id; diff --git a/src/database/AlbumRepository.cpp b/src/database/AlbumRepository.cpp index 16e9f40..05b0a2a 100644 --- a/src/database/AlbumRepository.cpp +++ b/src/database/AlbumRepository.cpp @@ -29,6 +29,51 @@ std::vector database::AlbumRepository::retrieveRecords() return albums; } + +std::pair database::AlbumRepository::retrieveRecordWithSongCount(model::Album& album, type::AlbumFilter filter = type::AlbumFilter::id) +{ + std::stringstream qry; + auto conn = setupMysqlConnection(); + auto stmt = mysql_stmt_init(conn); + + MYSQL_BIND params[4]; + std::memset(params, 0, sizeof(params)); + + qry << "SELECT alb.*, COUNT(*) AS SongCount FROM Album alb LEFT JOIN "; + qry << "Song sng ON alb.AlbumId=sng.AlbumId WHERE "; + + switch (filter) { + case type::AlbumFilter::id: + qry << "alb.AlbumId = ?"; + + params[0].buffer_type = MYSQL_TYPE_LONG; + params[0].buffer = (char*)&album.id; + params[0].length = 0; + params[0].is_null = 0; + break; + default: + break; + } + qry << " GROUP BY alb.AlbumId LIMIT 1"; + + const auto query = qry.str(); + + auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); + status = mysql_stmt_bind_param(stmt, params); + status = mysql_stmt_execute(stmt); + + std::cout << "query has been performed" << std::endl; + + auto albWSC = parseRecordWithSongCount(stmt); + + mysql_stmt_close(stmt); + mysql_close(conn); + + std::cout << "record has been parsed" << std::endl; + + return albWSC; +} + model::Album database::AlbumRepository::retrieveRecord(model::Album& album, type::AlbumFilter filter) { std::cout << "retrieving album record" << std::endl; @@ -165,9 +210,45 @@ void database::AlbumRepository::saveAlbum(const model::Album& album) std::cout << "done inserting album record" << std::endl; } +void database::AlbumRepository::deleteAlbum(const model::Album& album, type::AlbumFilter filter = type::AlbumFilter::id) +{ + std::cout << "deleting album record" << std::endl; + + std::stringstream qry; + auto conn = setupMysqlConnection(); + auto stmt = mysql_stmt_init(conn); + + MYSQL_BIND params[1]; + std::memset(params, 0, sizeof(params)); + + qry << "DELETE FROM Album WHERE "; + + switch (filter) { + case type::AlbumFilter::id: + qry << "AlbumId = ?"; + + params[0].buffer_type = MYSQL_TYPE_LONG; + params[0].buffer = (char*)&album.id; + params[0].length = 0; + params[0].is_null = 0; + break; + default: + break; + } + + const auto query = qry.str(); + + auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); + status = mysql_stmt_bind_param(stmt, params); + status = mysql_stmt_execute(stmt); + + std::cout << "execute delete query" << std::endl; +} + std::vector database::AlbumRepository::parseRecords(MYSQL_STMT* stmt) { + std::cout << "parsing album record" << std::endl; mysql_stmt_store_result(stmt); std::vector albums; @@ -225,6 +306,7 @@ std::vector database::AlbumRepository::parseRecords(MYSQL_STMT* st return albums; } +// TODO: check to see if this is not used, if not then remove it model::Album database::AlbumRepository::parseRecord(MYSQL_RES* results) { std::cout << "parsing album record" << std::endl; @@ -250,6 +332,65 @@ model::Album database::AlbumRepository::parseRecord(MYSQL_RES* results) return album; } +std::pair database::AlbumRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) +{ + std::cout << "parsing album record with song count" << std::endl; + mysql_stmt_store_result(stmt); + auto rowCount = mysql_stmt_num_rows(stmt); + std::cout << "result count " << rowCount << std::endl; + + model::Album album; + int songCount; + + if (mysql_stmt_field_count(stmt) == 0) { + std::cout << "field count is 0, must be an incorrect query" << std::endl; + return std::make_pair(model::Album(), 0); + } + + auto res = mysql_stmt_result_metadata(stmt); + const auto valAmt = 4; + const auto strLen = 1024; + unsigned long len[valAmt]; + my_bool nullRes[valAmt]; + + MYSQL_BIND val[valAmt]; + std::memset(val, 0, sizeof(val)); + + char title[strLen]; + + val[0].buffer_type = MYSQL_TYPE_LONG; + val[0].buffer = (char*)&album.id; + val[0].length = &len[0]; + val[0].is_null = &nullRes[0]; + + val[1].buffer_type = MYSQL_TYPE_STRING; + val[1].buffer = (char*)title; + val[1].buffer_length = strLen; + val[1].length = &len[1]; + val[1].is_null = &nullRes[1]; + + val[2].buffer_type = MYSQL_TYPE_LONG; + val[2].buffer = (char*)&album.year; + val[2].length = &len[2]; + val[2].is_null = &nullRes[2]; + + val[3].buffer_type = MYSQL_TYPE_LONG; + val[3].buffer = (char*)&songCount; + val[3].length = &len[2]; + val[3].is_null = &nullRes[2]; + + auto status = mysql_stmt_bind_result(stmt, val); + status = mysql_stmt_fetch(stmt); + + album.title = std::move(title); + + std::cout << "done parsing album record with song count" << std::endl; + + auto albWSC = std::make_pair(album, songCount); + + return albWSC; +} + model::Album database::AlbumRepository::parseRecord(MYSQL_STMT *stmt) { std::cout << "parsing album record" << std::endl; diff --git a/src/database/YearRepository.cpp b/src/database/YearRepository.cpp index 9004c0a..f99553c 100644 --- a/src/database/YearRepository.cpp +++ b/src/database/YearRepository.cpp @@ -211,6 +211,7 @@ model::Year database::YearRepository::parseRecord(MYSQL_RES *results) model::Year database::YearRepository::parseRecord(MYSQL_STMT *stmt) { // TODO: imeplement this + // I really thought that I had already done this model::Year year; diff --git a/src/manager/AlbumManager.cpp b/src/manager/AlbumManager.cpp index 380b61c..f539312 100644 --- a/src/manager/AlbumManager.cpp +++ b/src/manager/AlbumManager.cpp @@ -36,6 +36,23 @@ model::Album manager::AlbumManager::saveAlbum(const model::Song& song) return album; } + +void manager::AlbumManager::deleteAlbum(const model::Song& song) +{ + model::Album album(song); + + database::AlbumRepository albRepo(m_bConf); + auto albWSC = albRepo.retrieveRecordWithSongCount(album, type::AlbumFilter::id); + + if (albWSC.second > 1) { + std::cout << "album still contain songs related to it, will not delete" << std::endl; + return; + } + + std::cout << "safe to delete the album record" << std::endl; + albRepo.deleteAlbum(album, type::AlbumFilter::id); +} + void manager::AlbumManager::printAlbum(const model::Album& album) { std::cout << "\nalbum record" << std::endl; diff --git a/src/manager/CoverArtManager.cpp b/src/manager/CoverArtManager.cpp index 3de2bfc..c182f1a 100644 --- a/src/manager/CoverArtManager.cpp +++ b/src/manager/CoverArtManager.cpp @@ -1,9 +1,15 @@ #include "manager/CoverArtManager.h" +#include +#include + #include "database/CoverArtRepository.h" +#include "manager/DirectoryManager.h" #include "type/CoverFilter.h" #include "utility/MetadataRetriever.h" +namespace fs = std::filesystem; + manager::CoverArtManager::CoverArtManager(const std::string& configPath) : path(configPath) { } @@ -32,3 +38,29 @@ model::Cover manager::CoverArtManager::saveCover(const model::Song& song, std::s return cov; } + + +void manager::CoverArtManager::deleteCover(const model::Song& song) +{ + database::CoverArtRepository covRepo(m_bConf); + + model::Cover cov(song.coverArtId); + + cov = covRepo.retrieveRecord(cov, type::CoverFilter::id); + covRepo.deleteRecord(cov); + + auto paths = manager::DirectoryManager::pathConfigContent(m_bConf); + + const auto coverArtPath = paths["cover_root_path"].get(); + std::string stockCoverArtPath = coverArtPath; + stockCoverArtPath.append("CoverArt.png"); + + if (stockCoverArtPath.compare(cov.imagePath) != 0) { + fs::remove(cov.imagePath); + std::cout << "deleting cover art" << std::endl; + } else { + std::cout << "song contains the stock cover art, will not delete" << std::endl; + } + + manager::DirectoryManager::deleteDirectories(song, coverArtPath); +} diff --git a/src/manager/SongManager.cpp b/src/manager/SongManager.cpp index 928efed..7f0b36d 100644 --- a/src/manager/SongManager.cpp +++ b/src/manager/SongManager.cpp @@ -48,30 +48,18 @@ void manager::SongManager::deleteSong(model::Song& song) // TODO: handle what happens to miscellanes records // like Album, Artist, Genre, etc. when a song // is deleted - database::CoverArtRepository covRepo(m_bConf); database::SongRepository songRepo(m_bConf); song = songRepo.retrieveRecord(song, type::SongFilter::id); - songRepo.deleteRecord(song); - - model::Cover cov; - cov.id = song.coverArtId; - cov = covRepo.retrieveRecord(cov, type::CoverFilter::id); - covRepo.deleteRecord(cov); auto paths = manager::DirectoryManager::pathConfigContent(m_bConf); - const auto coverArtPath = paths["cover_root_path"].get(); - std::string stockCoverArtPath = coverArtPath; - stockCoverArtPath.append("CoverArt.png"); + deleteMisc(song); + + songRepo.deleteRecord(song); - if (stockCoverArtPath.compare(cov.imagePath) != 0) { - fs::remove(cov.imagePath); - std::cout << "deleting cover art" << std::endl; - } fs::remove(song.songPath); manager::DirectoryManager::deleteDirectories(song, paths["root_music_path"].get()); - manager::DirectoryManager::deleteDirectories(song, coverArtPath); } void manager::SongManager::printSong(const model::Song& song) @@ -111,6 +99,7 @@ void manager::SongManager::saveSongTemp(model::Song& song) song.songPath = tmpSongPath; } + void manager::SongManager::saveMisc(model::Song& song) { CoverArtManager covMgr(m_bConf); @@ -164,3 +153,18 @@ void manager::SongManager::saveMisc(model::Song& song) std::cout << "done with miscellaneous database records" << std::endl; } + +void manager::SongManager::deleteMisc(const model::Song& song) +{ + manager::CoverArtManager covMgr(m_bConf); + covMgr.deleteCover(song); + + manager::AlbumManager albMgr(m_bConf); + albMgr.deleteAlbum(song); + + manager::ArtistManager artMgr(m_bConf); + + manager::GenreManager gnrMgr(m_bConf); + + manager::YearManager yrMgr(m_bConf); +}