diff --git a/CMakeLists.txt b/CMakeLists.txt index d22d96e..f8783b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,9 +28,12 @@ set(SOURCES set(HEADERS include/component/AppComponent.hpp include/controller/AlbumController.hpp + include/controller/ArtistController.hpp include/controller/CoverArtController.hpp + include/controller/GenreController.hpp include/controller/LoginController.hpp include/controller/SongController.hpp + include/controller/YearController.hpp include/database/AlbumRepository.h include/database/ArtistRepository.h include/database/BaseRepository.h diff --git a/include/controller/AlbumController.hpp b/include/controller/AlbumController.hpp index 892d028..a58460d 100644 --- a/include/controller/AlbumController.hpp +++ b/include/controller/AlbumController.hpp @@ -1,5 +1,5 @@ -#ifndef COVERARTCONTROLLER_H_ -#define COVERARTCONTROLLER_H_ +#ifndef ALBUMCONTROLLER_H_ +#define ALBUMCONTROLLER_H_ #include #include @@ -53,7 +53,7 @@ namespace controller for (auto& albDb : albsDb) { auto alb = dto::AlbumDto::createShared(); alb->id = albDb.id; - alb->title = albDb.songTitle.c_str(); + alb->title = albDb.title.c_str(); alb->year = albDb.year; albums->pushBack(alb); @@ -69,14 +69,14 @@ namespace controller database::AlbumRepository albRepo(m_bConf); model::Album albDb(id); - OATPP_ASSERT_HTTP(albRepo.doesAlbumExist(albDb, type::AlbumFilter::id) , Status::CODE_403, "album does not exist"); + OATPP_ASSERT_HTTP(albRepo.doesAlbumExists(albDb, type::AlbumFilter::id) , Status::CODE_403, "album does not exist"); std::cout << "album exists" << std::endl; albDb = albRepo.retrieveRecord(albDb, type::AlbumFilter::id); auto album = dto::AlbumDto::createShared(); album->id = albDb.id; - album->title = albDb.songTitle.c_str(); + album->title = albDb.title.c_str(); album->year = albDb.year; return createDtoResponse(Status::CODE_200, album); diff --git a/include/controller/ArtistController.hpp b/include/controller/ArtistController.hpp new file mode 100644 index 0000000..ad6982b --- /dev/null +++ b/include/controller/ArtistController.hpp @@ -0,0 +1,90 @@ +#ifndef ARTISTCONTROLLER_H_ +#define ARTISTCONTROLLER_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "oatpp/core/data/stream/ChunkedBuffer.hpp" +#include "oatpp/core/data/stream/FileStream.hpp" +#include "oatpp/core/macro/codegen.hpp" +#include "oatpp/core/macro/component.hpp" +#include "oatpp/web/mime/multipart/InMemoryPartReader.hpp" +#include "oatpp/web/mime/multipart/Reader.hpp" +#include "oatpp/web/server/api/ApiController.hpp" + +#include "database/ArtistRepository.h" +#include "dto/ArtistDto.hpp" +#include "manager/ArtistManager.h" +#include "model/Models.h" +#include "type/Scopes.h" +#include "type/ArtistFilter.h" + +namespace fs = std::filesystem; + +namespace controller +{ + class ArtistController : public oatpp::web::server::api::ApiController + { + public: + ArtistController(std::string p, OATPP_COMPONENT(std::shared_ptr, objectMapper)) + : oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) + { } + + ArtistController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr, objectMapper)) + : oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) + { } + + #include OATPP_CODEGEN_BEGIN(ApiController) + + // endpoint for retrieving all artist records in json format + ENDPOINT("GET", "/api/v1/artist", artistRecords, + REQUEST(std::shared_ptr, request)) + { + std::cout << "starting process of retrieving artist" << std::endl; + database::ArtistRepository artRepo(m_bConf); + auto artsDb = artRepo.retrieveRecords(); + auto artists = oatpp::data::mapping::type::List::createShared(); + + for (auto& artDb : artsDb) { + auto art = dto::ArtistDto::createShared(); + art->id = artDb.id; + art->artist = artDb.artist.c_str(); + + artists->pushBack(art); + } + + return createDtoResponse(Status::CODE_200, artists); + } + + // endpoint for retrieving single artist record by the artist id in json format + ENDPOINT("GET", "/api/v1/artist/{id}", artistRecord, + PATH(Int32, id)) { + + database::ArtistRepository artRepo(m_bConf); + model::Artist artDb(id); + + OATPP_ASSERT_HTTP(artRepo.doesArtistExist(artDb, type::ArtistFilter::id) , Status::CODE_403, "artist does not exist"); + + std::cout << "artist exist" << std::endl; + artDb = artRepo.retrieveRecord(artDb, type::ArtistFilter::id); + + auto artist = dto::ArtistDto::createShared(); + artist->id = artDb.id; + artist->artist = artDb.artist.c_str(); + + return createDtoResponse(Status::CODE_200, artist); + } + + #include OATPP_CODEGEN_END(ApiController) + private: + std::string m_exe_path; + model::BinaryPath m_bConf; + const long m_dataSize = std::numeric_limits::max(); + }; +} +#endif diff --git a/include/controller/GenreController.hpp b/include/controller/GenreController.hpp new file mode 100644 index 0000000..95fdfe4 --- /dev/null +++ b/include/controller/GenreController.hpp @@ -0,0 +1,90 @@ +#ifndef GENRECONTROLLER_H_ +#define GENRECONTROLLER_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "oatpp/core/data/stream/ChunkedBuffer.hpp" +#include "oatpp/core/data/stream/FileStream.hpp" +#include "oatpp/core/macro/codegen.hpp" +#include "oatpp/core/macro/component.hpp" +#include "oatpp/web/mime/multipart/InMemoryPartReader.hpp" +#include "oatpp/web/mime/multipart/Reader.hpp" +#include "oatpp/web/server/api/ApiController.hpp" + +#include "database/GenreRepository.h" +#include "dto/GenreDto.hpp" +#include "manager/GenreManager.h" +#include "model/Models.h" +#include "type/Scopes.h" +#include "type/GenreFilter.h" + +namespace fs = std::filesystem; + +namespace controller +{ + class GenreController : public oatpp::web::server::api::ApiController + { + public: + GenreController(std::string p, OATPP_COMPONENT(std::shared_ptr, objectMapper)) + : oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) + { } + + GenreController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr, objectMapper)) + : oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) + { } + + #include OATPP_CODEGEN_BEGIN(ApiController) + + // endpoint for retrieving all genre records in json format + ENDPOINT("GET", "/api/v1/genre", genreRecords, + REQUEST(std::shared_ptr, request)) + { + std::cout << "starting process of retrieving genre" << std::endl; + database::GenreRepository gnrRepo(m_bConf); + auto gnrsDb = gnrRepo.retrieveRecords(); + auto genres = oatpp::data::mapping::type::List::createShared(); + + for (auto& gnrDb : gnrsDb) { + auto gnr = dto::GenreDto::createShared(); + gnr->id = gnrDb.id; + gnr->category = gnrDb.category.c_str(); + + genres->pushBack(gnr); + } + + return createDtoResponse(Status::CODE_200, genres); + } + + // endpoint for retrieving single genre record by the genre id in json format + ENDPOINT("GET", "/api/v1/genre/{id}", genreRecord, + PATH(Int32, id)) { + + database::GenreRepository gnrRepo(m_bConf); + model::Genre gnrDb(id); + + OATPP_ASSERT_HTTP(gnrRepo.doesGenreExist(gnrDb, type::GenreFilter::id) , Status::CODE_403, "genre does not exist"); + + std::cout << "genre exist" << std::endl; + gnrDb = gnrRepo.retrieveRecord(gnrDb, type::GenreFilter::id); + + auto genre = dto::GenreDto::createShared(); + genre->id = gnrDb.id; + genre->category= gnrDb.category.c_str(); + + return createDtoResponse(Status::CODE_200, genre); + } + + #include OATPP_CODEGEN_END(ApiController) + private: + std::string m_exe_path; + model::BinaryPath m_bConf; + const long m_dataSize = std::numeric_limits::max(); + }; +} +#endif diff --git a/include/controller/YearController.hpp b/include/controller/YearController.hpp new file mode 100644 index 0000000..3cb8198 --- /dev/null +++ b/include/controller/YearController.hpp @@ -0,0 +1,90 @@ +#ifndef YEARCONTROLLER_H_ +#define YEARCONTROLLER_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "oatpp/core/data/stream/ChunkedBuffer.hpp" +#include "oatpp/core/data/stream/FileStream.hpp" +#include "oatpp/core/macro/codegen.hpp" +#include "oatpp/core/macro/component.hpp" +#include "oatpp/web/mime/multipart/InMemoryPartReader.hpp" +#include "oatpp/web/mime/multipart/Reader.hpp" +#include "oatpp/web/server/api/ApiController.hpp" + +#include "database/YearRepository.h" +#include "dto/YearDto.hpp" +#include "manager/YearManager.h" +#include "model/Models.h" +#include "type/Scopes.h" +#include "type/YearFilter.h" + +namespace fs = std::filesystem; + +namespace controller +{ + class YearController : public oatpp::web::server::api::ApiController + { + public: + YearController(std::string p, OATPP_COMPONENT(std::shared_ptr, objectMapper)) + : oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) + { } + + YearController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr, objectMapper)) + : oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) + { } + + #include OATPP_CODEGEN_BEGIN(ApiController) + + // endpoint for retrieving all year records in json format + ENDPOINT("GET", "/api/v1/year", yearRecords, + REQUEST(std::shared_ptr, request)) + { + std::cout << "starting process of retrieving year" << std::endl; + database::YearRepository yrRepo(m_bConf); + auto yrsDb = yrRepo.retrieveRecords(); + auto yearRecs = oatpp::data::mapping::type::List::createShared(); + + for (auto& yrDb : yrsDb) { + auto yr = dto::YearDto::createShared(); + yr->id = yrDb.id; + yr->year = yrDb.year; + + yearRecs->pushBack(yr); + } + + return createDtoResponse(Status::CODE_200, yearRecs); + } + + // endpoint for retrieving single year record by the year id in json format + ENDPOINT("GET", "/api/v1/year/{id}", yearRecord, + PATH(Int32, id)) { + + database::YearRepository yrRepo(m_bConf); + model::Year yrDb(id); + + OATPP_ASSERT_HTTP(yrRepo.doesYearExist(yrDb, type::YearFilter::id) , Status::CODE_403, "year does not exist"); + + std::cout << "year exist" << std::endl; + yrDb = yrRepo.retrieveRecord(yrDb, type::YearFilter::id); + + auto year = dto::YearDto::createShared(); + year->id = yrDb.id; + year->year= yrDb.year; + + return createDtoResponse(Status::CODE_200, year); + } + + #include OATPP_CODEGEN_END(ApiController) + private: + std::string m_exe_path; + model::BinaryPath m_bConf; + const long m_dataSize = std::numeric_limits::max(); + }; +} +#endif diff --git a/include/database/AlbumRepository.h b/include/database/AlbumRepository.h index 9253467..3ccd37b 100644 --- a/include/database/AlbumRepository.h +++ b/include/database/AlbumRepository.h @@ -22,7 +22,7 @@ namespace database void saveAlbum(const model::Album&); private: - std::vector parseRecords(MYSQL_RES*); + std::vector parseRecords(MYSQL_STMT*); // TODO: after parseRecord(MYSQL_STMT*) is implemented remove // parseRecord(MYSQL_RES*) diff --git a/include/database/ArtistRepository.h b/include/database/ArtistRepository.h index 0c194f2..17fcca1 100644 --- a/include/database/ArtistRepository.h +++ b/include/database/ArtistRepository.h @@ -1,6 +1,8 @@ #ifndef ARTISTREPOSITORY_H_ #define ARTISTREPOSITORY_H_ +#include + #include "database/BaseRepository.h" #include "model/Models.h" #include "type/ArtistFilter.h" @@ -12,12 +14,16 @@ namespace database public: ArtistRepository(const model::BinaryPath&); + std::vector retrieveRecords(); + model::Artist retrieveRecord(model::Artist&, type::ArtistFilter); bool doesArtistExist(const model::Artist&, type::ArtistFilter); void saveRecord(const model::Artist&); private: + std::vector parseRecords(MYSQL_STMT*); + // TODO: After parseRecord(MYSQL_STMT*) is implemented // remove parseRecord(MYSQL_RES*) model::Artist parseRecord(MYSQL_RES*); diff --git a/include/database/GenreRepository.h b/include/database/GenreRepository.h index 054ed04..88f66d9 100644 --- a/include/database/GenreRepository.h +++ b/include/database/GenreRepository.h @@ -1,6 +1,8 @@ #ifndef GENREREPOSITORY_H_ #define GENREREPOSITORY_H_ +#include + #include "database/BaseRepository.h" #include "model/Models.h" #include "type/GenreFilter.h" @@ -12,12 +14,16 @@ namespace database public: GenreRepository(const model::BinaryPath&); + std::vector retrieveRecords(); + model::Genre retrieveRecord(model::Genre&, type::GenreFilter); bool doesGenreExist(const model::Genre&, type::GenreFilter); void saveRecord(const model::Genre&); private: + std::vector parseRecords(MYSQL_STMT*); + // TODO: After parseRecord(MYSQL_STMT*) is implemented // remove parseRecord(MYSQL_RES*) model::Genre parseRecord(MYSQL_RES*); diff --git a/include/database/YearRepository.h b/include/database/YearRepository.h index a8e1215..dbe9164 100644 --- a/include/database/YearRepository.h +++ b/include/database/YearRepository.h @@ -1,6 +1,8 @@ #ifndef YEARREPOSITORY_H_ #define YEARREPOSITORY_H_ +#include + #include "database/BaseRepository.h" #include "model/Models.h" #include "type/YearFilter.h" @@ -12,12 +14,16 @@ namespace database public: YearRepository(const model::BinaryPath&); + std::vector retrieveRecords(); + model::Year retrieveRecord(model::Year&, type::YearFilter); bool doesYearExist(const model::Year&, type::YearFilter); void saveRecord(const model::Year&); private: + std::vector parseRecords(MYSQL_STMT*); + // TODO: After parseRecord(MYSQL_STMT*) is implemented // remove parseRecord(MYSQL_RES*) model::Year parseRecord(MYSQL_RES*); diff --git a/include/model/Models.h b/include/model/Models.h index b3f78bb..8e21dba 100644 --- a/include/model/Models.h +++ b/include/model/Models.h @@ -31,6 +31,9 @@ namespace model struct Artist { + Artist() = default; + Artist(const int id) : id(id) { } + int id; std::string artist; }; @@ -48,6 +51,9 @@ namespace model struct Genre { + Genre() = default; + Genre(const int id) : id(id) { } + int id; std::string category; @@ -55,6 +61,9 @@ namespace model struct Year { + Year() = default; + Year(const int id) : id(id) { } + int id; int year; }; diff --git a/src/Main.cpp b/src/Main.cpp index d9023d0..768f741 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -10,27 +10,38 @@ #include "oatpp/web/server/HttpConnectionHandler.hpp" #include "component/AppComponent.hpp" +#include "controller/ArtistController.hpp" +#include "controller/AlbumController.hpp" #include "controller/CoverArtController.hpp" +#include "controller/GenreController.hpp" #include "controller/LoginController.hpp" #include "controller/SongController.hpp" +#include "controller/YearController.hpp" #include "model/Models.h" namespace fs = std::filesystem; -//void run(const std::string& working_path) void run(const model::BinaryPath& bConf) { component::AppComponent component; OATPP_COMPONENT(std::shared_ptr, router); + auto albumController = std::make_shared(bConf); + auto artistController = std::make_shared(bConf); auto coverArtController = std::make_shared(bConf); + auto gnrController = std::make_shared(bConf); auto logController = std::make_shared(bConf); auto sngController = std::make_shared(bConf); + auto yearController = std::make_shared(bConf); + albumController->addEndpointsToRouter(router); + artistController->addEndpointsToRouter(router); coverArtController->addEndpointsToRouter(router); + gnrController->addEndpointsToRouter(router); logController->addEndpointsToRouter(router); sngController->addEndpointsToRouter(router); + yearController->addEndpointsToRouter(router); OATPP_COMPONENT(std::shared_ptr, connectionHandler); diff --git a/src/database/AlbumRepository.cpp b/src/database/AlbumRepository.cpp index 9b89165..16e9f40 100644 --- a/src/database/AlbumRepository.cpp +++ b/src/database/AlbumRepository.cpp @@ -1,6 +1,7 @@ #include "database/AlbumRepository.h" #include +#include #include #include #include @@ -11,10 +12,19 @@ database::AlbumRepository::AlbumRepository(const model::BinaryPath& bConf) { } -// TODO: implement this later on std::vector database::AlbumRepository::retrieveRecords() { - std::vector albums; + auto conn = setupMysqlConnection(); + auto stmt = mysql_stmt_init(conn); + + const std::string query = "SELECT * FROM Album"; + mysql_stmt_prepare(stmt, query.c_str(), query.size()); + mysql_stmt_execute(stmt); + + auto albums = parseRecords(stmt); + + mysql_stmt_close(stmt); + mysql_close(conn); return albums; } @@ -156,10 +166,61 @@ void database::AlbumRepository::saveAlbum(const model::Album& album) } -// TODO: implement this -std::vector database::AlbumRepository::parseRecords(MYSQL_RES* results) +std::vector database::AlbumRepository::parseRecords(MYSQL_STMT* stmt) { + mysql_stmt_store_result(stmt); + std::vector albums; + albums.reserve(mysql_stmt_num_rows(stmt)); + + const auto valAmt = 3; + unsigned long len[valAmt]; + my_bool nullRes[valAmt]; + + for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) { + if (mysql_stmt_field_count(stmt) > 0) { + model::Album alb; + auto res = mysql_stmt_result_metadata(stmt); + auto fields = mysql_fetch_fields(res); + const auto strLen = 1024; + + MYSQL_BIND val[valAmt]; + memset(val, 0, sizeof(val)); + + char title[strLen]; + + val[0].buffer_type = MYSQL_TYPE_LONG; + val[0].buffer = (char*)&alb.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*)&alb.year; + val[2].length = &len[2]; + val[2].is_null = &nullRes[2]; + + status = mysql_stmt_bind_result(stmt, val); + + while (true) { + std::cout << "fetching statement result" << std::endl; + status = mysql_stmt_fetch(stmt); + + if (status == 1 || status == MYSQL_NO_DATA) { + break; + } + + alb.title = title; + albums.push_back(std::move(alb)); + } + } + std::cout << "fetching next result" << std::endl; + } return albums; } diff --git a/src/database/ArtistRepository.cpp b/src/database/ArtistRepository.cpp index f2ca7ec..fc0b937 100644 --- a/src/database/ArtistRepository.cpp +++ b/src/database/ArtistRepository.cpp @@ -12,6 +12,24 @@ database::ArtistRepository::ArtistRepository(const model::BinaryPath& binConf) } +std::vector database::ArtistRepository::retrieveRecords() +{ + auto conn = setupMysqlConnection(); + auto stmt = mysql_stmt_init(conn); + const std::string query = "SELECT * FROM Artist"; + + mysql_stmt_prepare(stmt, query.c_str(), query.size()); + mysql_stmt_execute(stmt); + + auto artists = parseRecords(stmt); + + mysql_stmt_close(stmt); + mysql_close(conn); + + return artists; +} + + model::Artist database::ArtistRepository::retrieveRecord(model::Artist& artist, type::ArtistFilter filter) { std::cout << "retrieving artist record" << std::endl; @@ -23,7 +41,6 @@ model::Artist database::ArtistRepository::retrieveRecord(model::Artist& artist, MYSQL_BIND params[1]; memset(params, 0, sizeof(params)); - //std::unique_ptr param; auto artistLength = artist.artist.size(); switch (filter) { case type::ArtistFilter::id: @@ -36,8 +53,7 @@ model::Artist database::ArtistRepository::retrieveRecord(model::Artist& artist, break; case type::ArtistFilter::artist: qry << "art.Artist = ?"; - //param = std::make_unique(new char[artist.artist.size()]); - //mysql_real_escape_string(conn, *param, artist.artist.c_str(), artist.artist.size()); + params[0].buffer_type = MYSQL_TYPE_STRING; params[0].buffer = (char*)artist.artist.c_str(); params[0].length = &artistLength; @@ -145,6 +161,57 @@ void database::ArtistRepository::saveRecord(const model::Artist& artist) } +std::vector database::ArtistRepository::parseRecords(MYSQL_STMT *stmt) +{ + mysql_stmt_store_result(stmt); + + std::vector artists; + artists.reserve(mysql_stmt_num_rows(stmt)); + + if (mysql_stmt_field_count(stmt) == 0) { + std::cout << "field count is 0" << std::endl; + return artists; + } + + model::Artist art; + const auto valAmt = 2; + unsigned long len[valAmt]; + my_bool nullRes[valAmt]; + + auto res = mysql_stmt_result_metadata(stmt); + auto fields = mysql_fetch_fields(res); + const auto strLen = 1024; + + char artist[strLen]; + + MYSQL_BIND val[valAmt]; + memset(val, 0, sizeof(val)); + + val[0].buffer_type = MYSQL_TYPE_LONG; + val[0].buffer = (char*)&art.id; + val[0].length = &len[0]; + val[0].is_null = &nullRes[0]; + + val[1].buffer_type = MYSQL_TYPE_STRING; + val[1].buffer = (char*)artist; + val[1].buffer_length = strLen; + val[1].length = &len[1]; + val[1].is_null = &nullRes[1]; + + for (auto status = mysql_stmt_bind_result(stmt, val); status == 0; ) { + std::cout << "fetching statement result" << std::endl; + status = mysql_stmt_fetch(stmt); + + if (status == 0) { + art.artist = artist; + artists.push_back(std::move(art)); + } + } + + return artists; +} + + model::Artist database::ArtistRepository::parseRecord(MYSQL_RES* results) { std::cout << "parsing artist record" << std::endl; diff --git a/src/database/GenreRepository.cpp b/src/database/GenreRepository.cpp index a783bae..9be9e2e 100644 --- a/src/database/GenreRepository.cpp +++ b/src/database/GenreRepository.cpp @@ -10,8 +10,28 @@ database::GenreRepository::GenreRepository(const model::BinaryPath& bConf) { } +std::vector database::GenreRepository::retrieveRecords() +{ + auto conn = setupMysqlConnection(); + auto stmt = mysql_stmt_init(conn); + const std::string query = "SELECT * FROM Genre"; + + mysql_stmt_prepare(stmt, query.c_str(), query.size()); + mysql_stmt_execute(stmt); + + auto genres = parseRecords(stmt); + + mysql_stmt_close(stmt); + mysql_close(conn); + + return genres; +} + + model::Genre database::GenreRepository::retrieveRecord(model::Genre& genre, type::GenreFilter filter) { + // TODO: change to prepared statement + std::cout << "retrieving genre record" << std::endl; std::stringstream qry; auto conn = setupMysqlConnection(); @@ -125,6 +145,57 @@ void database::GenreRepository::saveRecord(const model::Genre& genre) std::cout << "inserted record" << std::endl; } + +std::vector database::GenreRepository::parseRecords(MYSQL_STMT *stmt) +{ + mysql_stmt_store_result(stmt); + + std::vector genres; + genres.reserve(mysql_stmt_num_rows(stmt)); + + if (mysql_stmt_field_count(stmt) == 0) { + std::cout << "field count is 0" << std::endl; + return genres; + } + + model::Genre gnr; + const auto valAmt = 2; + unsigned long len[valAmt]; + my_bool nullRes[valAmt]; + + auto res = mysql_stmt_result_metadata(stmt); + auto fields = mysql_fetch_fields(res); + const auto strLen = 1024; + + char category[strLen]; + + MYSQL_BIND val[valAmt]; + memset(val, 0, sizeof(val)); + + val[0].buffer_type = MYSQL_TYPE_LONG; + val[0].buffer = (char*)&gnr.id; + val[0].length = &len[0]; + val[0].is_null = &nullRes[0]; + + val[1].buffer_type = MYSQL_TYPE_STRING; + val[1].buffer = (char*)category; + val[1].buffer_length = strLen; + val[1].length = &len[1]; + val[1].is_null = &nullRes[1]; + + for (auto status = mysql_stmt_bind_result(stmt, val); status == 0;) { + std::cout << "fetching statement result" << std::endl; + status = mysql_stmt_fetch(stmt); + + if (status == 0) { + gnr.category = category; + genres.push_back(std::move(gnr)); + } + } + + return genres; +} + model::Genre database::GenreRepository::parseRecord(MYSQL_RES* results) { std::cout << "parsing genre record" << std::endl; diff --git a/src/database/YearRepository.cpp b/src/database/YearRepository.cpp index 4cd8676..9004c0a 100644 --- a/src/database/YearRepository.cpp +++ b/src/database/YearRepository.cpp @@ -12,8 +12,26 @@ database::YearRepository::YearRepository(const model::BinaryPath& bConf) { } +std::vector database::YearRepository::retrieveRecords() +{ + auto conn = setupMysqlConnection(); + auto stmt = mysql_stmt_init(conn); + const std::string query = "SELECT * FROM Year"; + + mysql_stmt_prepare(stmt, query.c_str(), query.size()); + mysql_stmt_execute(stmt); + + auto yearRecs = parseRecords(stmt); + + mysql_stmt_close(stmt); + mysql_close(conn); + + return yearRecs; +} + model::Year database::YearRepository::retrieveRecord(model::Year& year, type::YearFilter filter) { + // TODO: switch to prepared statements std::cout << "retrieving year record" << std::endl; std::stringstream qry; auto conn = setupMysqlConnection(); @@ -46,7 +64,6 @@ model::Year database::YearRepository::retrieveRecord(model::Year& year, type::Ye bool database::YearRepository::doesYearExist(const model::Year& year, type::YearFilter filter) { - // TODO: implement this auto conn = setupMysqlConnection(); auto stmt = mysql_stmt_init(conn); @@ -123,6 +140,51 @@ void database::YearRepository::saveRecord(const model::Year& year) std::cout << "saved record" << std::endl; } + +std::vector database::YearRepository::parseRecords(MYSQL_STMT *stmt) +{ + mysql_stmt_store_result(stmt); + + std::vector yearRecs; + yearRecs.reserve(mysql_stmt_num_rows(stmt)); + + if (mysql_stmt_field_count(stmt) == 0) { + std::cout << "field count is 0" << std::endl; + return yearRecs; + } + + model::Year yearRec; + const auto valAmt = 2; + unsigned long len[valAmt]; + my_bool nullRes[valAmt]; + + auto res = mysql_stmt_result_metadata(stmt); + + MYSQL_BIND val[valAmt]; + memset(val, 0, sizeof(val)); + + val[0].buffer_type = MYSQL_TYPE_LONG; + val[0].buffer = (char*)&yearRec.id; + val[0].length = &len[0]; + val[0].is_null = &nullRes[0]; + + val[1].buffer_type = MYSQL_TYPE_LONG; + val[1].buffer = (char*)&yearRec.year; + val[1].length = &len[1]; + val[1].is_null = &nullRes[1]; + + for (auto status = mysql_stmt_bind_result(stmt, val); status == 0;) { + std::cout << "fetching statement result" << std::endl; + status = mysql_stmt_fetch(stmt); + + if (status == 0) { + yearRecs.push_back(std::move(yearRec)); + } + } + + return yearRecs; +} + model::Year database::YearRepository::parseRecord(MYSQL_RES *results) { std::cout << "parsing year record" << std::endl;