diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index a87d5ea61fd8504ff60fac72672d6f00da9fb499..a653b0520ca0f4355f27a34c5e144f31449c1fb5 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -1,20 +1,20 @@ set(CMAKE_PREFIX_PATH build) project(SourcedOut CXX) find_package(Boost 1.81.0 REQUIRED) -IF(APPLE) +IF (APPLE) set(CMAKE_THREAD_LIBS_INIT "-lpthread") set(CMAKE_HAVE_THREADS_LIBRARY 1) set(CMAKE_USE_WIN32_THREADS_INIT 0) set(CMAKE_USE_PTHREADS_INIT 1) set(THREADS_PREFER_PTHREAD_FLAG ON) -ELSE() +ELSE () find_package(Threads REQUIRED) -ENDIF() +ENDIF () find_library(PQXX_LIB pqxx) -#find_package(libpqxx REQUIRED) + find_package(GTest REQUIRED) -#find_package(nlohmann_json REQUIRED) + message(STATUS ${nlohmann_json_LIBRARIES}) set(THREADS_PREFER_PTHREAD_FLAG ON) diff --git a/server/internal/dbManager/include/dbConnection.hpp b/server/internal/dbManager/include/dbConnection.hpp deleted file mode 100644 index 375aecbb19e2c1f8920220018a3583d8ac884a9f..0000000000000000000000000000000000000000 --- a/server/internal/dbManager/include/dbConnection.hpp +++ /dev/null @@ -1,25 +0,0 @@ - -#ifndef SOURCEDOUT_DBCONNECTION_HPP -#define SOURCEDOUT_DBCONNECTION_HPP - -#include -// #include "dotenv.h" -// using namespace dotenv; -class dbConnection { - public: - dbConnection(); - [[nodiscard]] std::shared_ptr connection() const; - - private: - void establish_connection(); - - std::string m_dbhost = "localhost"; - int m_dbport = 5432; - std::string m_dbname = "demo"; - std::string m_dbuser = "postgres"; - std::string m_dbpass = "postgres"; - - std::shared_ptr m_connection; -}; - -#endif // SOURCEDOUT_DBCONNECTION_HPP diff --git a/server/internal/dbManager/include/dbManager.hpp b/server/internal/dbManager/include/dbManager.hpp index 7c0202adf0464d48e81c59099a07e48a66264ebb..55ed0314c7f00e3d683db0ae963fc339b78276e6 100644 --- a/server/internal/dbManager/include/dbManager.hpp +++ b/server/internal/dbManager/include/dbManager.hpp @@ -10,18 +10,18 @@ #include #include -// #include "dotenv.h" -// using namespace dotenv; + class dbManager { - public: +public: dbManager(); std::shared_ptr connection(); void freeConnection(const std::shared_ptr &); - private: - const size_t POOL_SIZE = 10; +private: + const size_t POOL_SIZE = std::getenv("POOL_SIZE") ? + std::stoul(std::getenv("POOL_SIZE")) : 10; std::condition_variable m_condition; void createPool(); diff --git a/server/internal/dbManager/src/dbConnection.cpp b/server/internal/dbManager/src/dbConnection.cpp deleted file mode 100644 index 3a6afad7222177dd83d86ceb2ac739d22638707e..0000000000000000000000000000000000000000 --- a/server/internal/dbManager/src/dbConnection.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// -// Created by qwert on 01.05.2023. -// - -// #include "../include/dbConnection.hpp" - -// #include - -// dbConnection::dbConnection() { establish_connection(); } - -// std::shared_ptr dbConnection::connection() const { return m_connection; } - -// // void dbConnection::establish_connection() { -// // pqxx::connection c("dbname =mydb" "user = temp password =temp hostaddr =db port = 5432"); -// // m_connection.reset(&c); - -// // } diff --git a/server/internal/dbManager/src/dbManager.cpp b/server/internal/dbManager/src/dbManager.cpp index 7a1f01746d58ead91f9b1bdd8a2d5ebe5128a386..e6f6d723e3c6d64c2c102ba5ebf9b16f6311aa8b 100644 --- a/server/internal/dbManager/src/dbManager.cpp +++ b/server/internal/dbManager/src/dbManager.cpp @@ -6,7 +6,7 @@ dbManager::dbManager() { createPool(); } void dbManager::createPool() { std::lock_guard locker_(m_mutex); - for (auto i = 0; i < POOL_SIZE; i++) { + for (size_t i = 0; i < POOL_SIZE; i++) { connection_pool.emplace(std::make_shared()); } } diff --git a/server/internal/entities/include/Solution.hpp b/server/internal/entities/include/Solution.hpp index 9a0b49ee3d41f61594ae986b28323eeacb2f92be..c9c1f4c00bcd26eb592d0cc77c55a7147151c76c 100644 --- a/server/internal/entities/include/Solution.hpp +++ b/server/internal/entities/include/Solution.hpp @@ -6,12 +6,16 @@ #include class Solution { - public: - Solution(size_t id, std::string sendDate, size_t senderId, std::string source, size_t taskId, std::string result, - std::string tokens, std::string astTree, size_t orig_solution, std::string language) noexcept; +public: + Solution(size_t id, std::string sendDate, size_t senderId, + std::string source, size_t taskId, std::string result, + std::string tokens, std::string astTree, size_t orig_solution, + std::string language) noexcept; - Solution(std::string sendDate, size_t senderId, std::string source, size_t taskId, std::string result, - std::string tokens, std::string astTree, size_t orig_solution, std::string language) noexcept; + Solution(std::string sendDate, size_t senderId, + std::string source, size_t taskId, std::string result, + std::string tokens, std::string astTree, + size_t orig_solution, std::string language) noexcept; Solution() noexcept; @@ -59,7 +63,7 @@ class Solution { bool operator!=(const Solution &rhs) const noexcept; - private: +private: size_t id; std::string send_date; size_t sender_id; diff --git a/server/internal/entities/src/MetricStat.cpp b/server/internal/entities/src/MetricStat.cpp index 86fed05b69ce89c64aca8131be2d94f18e742eec..0e91088144d8f71cb4dbcddecac229a7c0ff2c01 100644 --- a/server/internal/entities/src/MetricStat.cpp +++ b/server/internal/entities/src/MetricStat.cpp @@ -3,26 +3,26 @@ MetricStat::MetricStat(unsigned long solutionId, float textBasedRes, float tokenBasedRes, float treeBasedRes, bool verdict, float meanRes) noexcept - : id(0), - solution_id(solutionId), - text_based_res(textBasedRes), - token_based_res(tokenBasedRes), - tree_based_res(treeBasedRes), - verdict(verdict), - mean_res(meanRes) {} + : id(0), + solution_id(solutionId), + text_based_res(textBasedRes), + token_based_res(tokenBasedRes), + tree_based_res(treeBasedRes), + verdict(verdict), + mean_res(meanRes) {} MetricStat::MetricStat(size_t id, size_t solutionId, float textBasedRes, float tokenBasedRes, float treeBasedRes, bool verdict, float meanRes) noexcept - : id(id), - solution_id(solutionId), - text_based_res(textBasedRes), - token_based_res(tokenBasedRes), - tree_based_res(treeBasedRes), - verdict(verdict), - mean_res(meanRes) {} + : id(id), + solution_id(solutionId), + text_based_res(textBasedRes), + token_based_res(tokenBasedRes), + tree_based_res(treeBasedRes), + verdict(verdict), + mean_res(meanRes) {} MetricStat::MetricStat() noexcept - : id(0), solution_id(0), text_based_res(0), token_based_res(0), tree_based_res(), verdict(true), mean_res(0) {} + : id(0), solution_id(0), text_based_res(0), token_based_res(0), tree_based_res(), verdict(true), mean_res(0) {} size_t MetricStat::getId() const noexcept { return id; } diff --git a/server/internal/entities/src/Solution.cpp b/server/internal/entities/src/Solution.cpp index 0dfebf14677be85b002a6f4b7eaf2b447d270abe..33d8c7edb1dfe53cf9d9cc8aa729766126fb18f5 100644 --- a/server/internal/entities/src/Solution.cpp +++ b/server/internal/entities/src/Solution.cpp @@ -7,29 +7,29 @@ Solution::Solution(size_t id, std::string sendDate, size_t senderId, std::string source, size_t taskId, std::string result, std::string tokens, std::string astTree, size_t orig_solution, std::string language_) noexcept - : id(id), - send_date(std::move(sendDate)), - sender_id(senderId), - source(std::move(source)), - tokens(std::move(tokens)), - astTree(std::move(astTree)), - task_id(taskId), - result(std::move(result)), - orig_solution(orig_solution), - language(std::move(language_)) {} + : id(id), + send_date(std::move(sendDate)), + sender_id(senderId), + source(std::move(source)), + tokens(std::move(tokens)), + astTree(std::move(astTree)), + task_id(taskId), + result(std::move(result)), + orig_solution(orig_solution), + language(std::move(language_)) {} Solution::Solution(std::string sendDate, size_t senderId, std::string source, size_t taskId, std::string result, std::string tokens, std::string astTree, size_t orig_solution, std::string language_) noexcept - : id(0), - send_date(std::move(sendDate)), - sender_id(senderId), - source(std::move(source)), - tokens(std::move(tokens)), - astTree(std::move(astTree)), - task_id(taskId), - result(std::move(result)), - orig_solution(orig_solution), - language(std::move(language_)) {} + : id(0), + send_date(std::move(sendDate)), + sender_id(senderId), + source(std::move(source)), + tokens(std::move(tokens)), + astTree(std::move(astTree)), + task_id(taskId), + result(std::move(result)), + orig_solution(orig_solution), + language(std::move(language_)) {} size_t Solution::getId() const noexcept { return id; } @@ -71,7 +71,7 @@ size_t Solution::getOrigSolution() const { return orig_solution; } void Solution::setOrigSolution(size_t origSolution) { orig_solution = origSolution; } -Solution::Solution() noexcept : id(0), sender_id(0), task_id(0) {} +Solution::Solution() noexcept: id(0), sender_id(0), task_id(0) {} const std::string &Solution::getLanguage() const { return language; } diff --git a/server/internal/entities/src/Task.cpp b/server/internal/entities/src/Task.cpp index c0c3586da38e09ccc1c45aa0aaf1971d741cc980..77d471c3f2ec4888715938b1243e28d3f10efc29 100644 --- a/server/internal/entities/src/Task.cpp +++ b/server/internal/entities/src/Task.cpp @@ -4,12 +4,12 @@ #include Task::Task(std::string description_, float treshold_, std::string name_) noexcept - : id(0), description(std::move(description_)), treshhold(treshold_), name(std::move(name_)) {} + : id(0), description(std::move(description_)), treshhold(treshold_), name(std::move(name_)) {} Task::Task(size_t id, std::string description_, float treshold_, std::string name_) noexcept - : id(id), description(std::move(description_)), treshhold(treshold_), name(std::move(name_)) {} + : id(id), description(std::move(description_)), treshhold(treshold_), name(std::move(name_)) {} -Task::Task() noexcept : id(0), treshhold(0) {} +Task::Task() noexcept: id(0), treshhold(0) {} unsigned long Task::getId() const noexcept { return id; } diff --git a/server/internal/entities/src/User.cpp b/server/internal/entities/src/User.cpp index f4795d7eddeba2f688d5fc90b4f90abdae3fb1d4..34289fd91a37b0c6bef1ea84b1e3026fa22b83eb 100644 --- a/server/internal/entities/src/User.cpp +++ b/server/internal/entities/src/User.cpp @@ -3,12 +3,12 @@ #include User::User(size_t id_, std::string login_, std::string password_, std::string username_) noexcept - : id(id_), login(std::move(login_)), password(std::move(password_)), username(std::move(username_)) {} + : id(id_), login(std::move(login_)), password(std::move(password_)), username(std::move(username_)) {} User::User(std::string login_, std::string password_, std::string username_) noexcept - : id(0), login(std::move(login_)), password(std::move(password_)), username(std::move(username_)) {} + : id(0), login(std::move(login_)), password(std::move(password_)), username(std::move(username_)) {} -User::User() noexcept : id(0) {} +User::User() noexcept: id(0) {} const std::string &User::getLogin() const noexcept { return login; } diff --git a/server/internal/repository/include/MetricRepository.hpp b/server/internal/repository/include/MetricRepository.hpp index ca0fa5fe84e2ea374c5dce596baa01acb1a3e8ac..090ddcad6a5db3475b3da2d62c0bfa2b4b5532e4 100644 --- a/server/internal/repository/include/MetricRepository.hpp +++ b/server/internal/repository/include/MetricRepository.hpp @@ -10,7 +10,7 @@ using namespace pqxx; class MetricRepository : public IMetricRepository { - public: +public: MetricRepository(); std::optional getById(size_t id) override; @@ -23,7 +23,7 @@ class MetricRepository : public IMetricRepository { void deleteMetricById(size_t id) override; - private: +private: std::shared_ptr manager; static MetricStat makeMetric(const result::const_iterator &c); diff --git a/server/internal/repository/include/SolutionRepository.hpp b/server/internal/repository/include/SolutionRepository.hpp index 04f5ae8ebf0833a763815d409b8bf32dd8da5a7d..323d4e4a19bb941597e682c0c5028dec19c4f57f 100644 --- a/server/internal/repository/include/SolutionRepository.hpp +++ b/server/internal/repository/include/SolutionRepository.hpp @@ -13,7 +13,7 @@ using namespace pqxx; class SolutionRepository : public ISolutionRepository { - public: +public: SolutionRepository(); std::optional getSolutionById(size_t id) override; @@ -36,7 +36,7 @@ class SolutionRepository : public ISolutionRepository { std::optional getOriginalSolution(size_t id) override; - private: +private: static Solution makeSolution(const result::const_iterator &c); std::shared_ptr manager; diff --git a/server/internal/repository/include/TaskRepository.hpp b/server/internal/repository/include/TaskRepository.hpp index 3bc409b3d7f2d1224775ed9c857796ccec1fa198..d9508c987efa55d7d726acf80df9cc117a44c69c 100644 --- a/server/internal/repository/include/TaskRepository.hpp +++ b/server/internal/repository/include/TaskRepository.hpp @@ -12,13 +12,14 @@ using namespace pqxx; class TaskRepository : public ITaskRepository { - public: +public: TaskRepository(); + std::optional getTaskById(size_t id) override; std::vector getAllTasks() override; - void updateTask(const Task& task) override; + void updateTask(const Task &task) override; size_t storeTask(Task task) override; @@ -26,8 +27,8 @@ class TaskRepository : public ITaskRepository { void deleteTaskById(size_t task_id) override; - private: - static Task makeTask(const result::const_iterator& c); +private: + static Task makeTask(const result::const_iterator &c); std::shared_ptr manager; }; diff --git a/server/internal/repository/include/UserRepository.hpp b/server/internal/repository/include/UserRepository.hpp index 136e5cdeff011593e6b23cd19ac0b6c16241d06b..29cb3bd0d5a1f5a3a46b2db82e2e3f7a528f0f5e 100644 --- a/server/internal/repository/include/UserRepository.hpp +++ b/server/internal/repository/include/UserRepository.hpp @@ -13,7 +13,7 @@ using namespace pqxx; class UserRepository : public IUserRepository { - public: +public: UserRepository(); std::optional getUserById(size_t id) override; @@ -30,7 +30,7 @@ class UserRepository : public IUserRepository { void update(User user) override; - private: +private: static User makeUser(const result::const_iterator &c); std::shared_ptr manager; diff --git a/server/internal/repository/src/MetricRepository.cpp b/server/internal/repository/src/MetricRepository.cpp index 33189de679cffaa322cbfc2a0105e58baf587818..b10b4caca9dcba34716d5464237588d6490f476b 100644 --- a/server/internal/repository/src/MetricRepository.cpp +++ b/server/internal/repository/src/MetricRepository.cpp @@ -1,15 +1,20 @@ -#include "MetricRepository.hpp" - #include #include "MetricStat.hpp" +#include "MetricRepository.hpp" + + +MetricRepository::MetricRepository() { manager = std::make_shared(); } + std::optional MetricRepository::getById(size_t id) { try { auto c = manager->connection(); + std::string sql = "SELECT * FROM metricStat WHERE id=" + std::to_string(id); nontransaction n(*c); result r(n.exec(sql)); + manager->freeConnection(c); if (r.empty()) return std::nullopt; return makeMetric(r.begin()); @@ -18,19 +23,22 @@ std::optional MetricRepository::getById(size_t id) { } } + size_t MetricRepository::storeMetric(MetricStat metric) { try { auto c = manager->connection(); - std::string sql = (boost::format("INSERT INTO metricStat (solution_id, text_based_res, token_based_res, " - "tree_based_res, verdict, mean_res) " - "VALUES ('%s', '%s', '%s', '%s', '%s', '%s') RETURNING id; ") % - metric.getSolutionId() % metric.getTextBasedRes() % metric.getTokenBasedRes() % - metric.getTreeBasedRes() % metric.isVerdict() % metric.getMeanRes()) - .str(); + std::string sql = (boost::format( + "INSERT INTO metricStat (solution_id, text_based_res, token_based_res, " + "tree_based_res, verdict, mean_res) " + "VALUES ('%s', '%s', '%s', '%s', '%s', '%s') RETURNING id; ") % + metric.getSolutionId() % metric.getTextBasedRes() % + metric.getTokenBasedRes() % metric.getTreeBasedRes() % + metric.isVerdict() % metric.getMeanRes()).str(); work w(*c); row r = (w.exec1(sql)); w.commit(); + manager->freeConnection(c); return r["id"].as(); } catch (...) { @@ -38,39 +46,48 @@ size_t MetricRepository::storeMetric(MetricStat metric) { } } + void MetricRepository::updateMetric(MetricStat metric) { try { auto c = manager->connection(); std::string sql = - (boost::format("UPDATE metricStat SET solution_id = '%s', text_based_res = '%s', token_based_res " - "= '%s', tree_based_res = '%s', verdict = '%s', mean_res = '%s';") % - metric.getSolutionId() % metric.getTextBasedRes() % metric.getTokenBasedRes() % metric.getTreeBasedRes() % - metric.isVerdict() % metric.getMeanRes()) - .str(); + (boost::format( + "UPDATE metricStat SET solution_id = '%s'," + " text_based_res = '%s', token_based_res = '%s'," + " tree_based_res = '%s', verdict = '%s', mean_res = '%s';") % + metric.getSolutionId() % metric.getTextBasedRes() % + metric.getTokenBasedRes() % metric.getTreeBasedRes() % + metric.isVerdict() % metric.getMeanRes()).str(); work w(*c); w.exec(sql); + manager->freeConnection(c); } catch (...) { throw; } } + void MetricRepository::deleteMetric(MetricStat metric) { deleteMetricById(metric.getId()); } + void MetricRepository::deleteMetricById(size_t id) { try { auto c = manager->connection(); + std::string sql = "DELETE FROM metricStat WHERE id=" + std::to_string(id); work w(*c); w.exec(sql); w.commit(); + manager->freeConnection(c); } catch (...) { throw; } } + MetricStat MetricRepository::makeMetric(const result::const_iterator &c) { return {c.at(c.column_number("id")).as(), c.at(c.column_number("solution_id")).as(), @@ -80,5 +97,3 @@ MetricStat MetricRepository::makeMetric(const result::const_iterator &c) { c.at(c.column_number("verdict")).as(), c.at(c.column_number("mean_res")).as()}; } - -MetricRepository::MetricRepository() { manager = std::make_shared(); } diff --git a/server/internal/repository/src/SolutionRepository.cpp b/server/internal/repository/src/SolutionRepository.cpp index 44b3b0bbd9148e8be24beea5d06bab5025d46511..c16fc797e062f93b9bc569c177be852cbb5ca5e7 100644 --- a/server/internal/repository/src/SolutionRepository.cpp +++ b/server/internal/repository/src/SolutionRepository.cpp @@ -1,19 +1,25 @@ -#include "SolutionRepository.hpp" - #include #include #include #include "Solution.hpp" +#include "SolutionRepository.hpp" + using namespace pqxx; + +SolutionRepository::SolutionRepository() { manager = std::make_shared(); } + + std::optional SolutionRepository::getSolutionById(size_t id) { try { auto c = manager->connection(); + std::string sql = "SELECT * FROM solutions WHERE id=" + std::to_string(id); nontransaction n(*c); result r(n.exec(sql)); + manager->freeConnection(c); if (r.empty()) return std::nullopt; return makeSolution(r.begin()); @@ -22,21 +28,26 @@ std::optional SolutionRepository::getSolutionById(size_t id) { } } + std::vector SolutionRepository::getSolutionsBySenderId(size_t sender_id) { try { auto c = manager->connection(); + std::string sql = "SELECT * FROM solutions WHERE sender_id=" + std::to_string(sender_id); nontransaction n(*c); auto stream = stream_from::query(n, sql); std::vector solutions; - std::tuple - row; + std::tuple row; while (stream >> row) { - solutions.emplace_back(get<0>(row), get<1>(row), get<2>(row), get<3>(row), get<4>(row), get<5>(row), - get<6>(row), get<7>(row), get<8>(row), get<9>(row)); + solutions.emplace_back(get<0>(row), get<1>(row), + get<2>(row), get<3>(row), + get<4>(row), get<5>(row), + get<6>(row), get<7>(row), + get<8>(row), get<9>(row)); } stream.complete(); + manager->freeConnection(c); return solutions; } catch (...) { @@ -44,21 +55,26 @@ std::vector SolutionRepository::getSolutionsBySenderId(size_t sender_i } } + std::vector SolutionRepository::getSolutionsByTaskId(size_t task_id) { try { auto c = manager->connection(); + std::string sql = "SELECT * FROM solutions WHERE task_id=" + std::to_string(task_id); nontransaction n(*c); auto stream = stream_from::query(n, sql); std::vector solutions; - std::tuple - row; + std::tuple row; while (stream >> row) { - solutions.emplace_back(get<0>(row), get<1>(row), get<2>(row), get<3>(row), get<4>(row), get<5>(row), - get<6>(row), get<7>(row), get<8>(row), get<9>(row)); + solutions.emplace_back(get<0>(row), get<1>(row), + get<2>(row), get<3>(row), + get<4>(row), get<5>(row), + get<6>(row), get<7>(row), + get<8>(row), get<9>(row)); } stream.complete(); + manager->freeConnection(c); return solutions; } catch (...) { @@ -66,23 +82,29 @@ std::vector SolutionRepository::getSolutionsByTaskId(size_t task_id) { } } + std::vector SolutionRepository::getSolutionsByTaskIdAndSenderId(size_t task_id, size_t sender_id) { try { auto c = manager->connection(); + std::string sql = - (boost::format("SELECT * FROM solutions WHERE task_id='%s' AND sender_id='%s'") % task_id % sender_id) - .str(); + (boost::format("SELECT * FROM solutions WHERE" + " task_id='%s' AND sender_id='%s'") % task_id % sender_id) + .str(); nontransaction n(*c); auto stream = stream_from::query(n, sql); std::vector solutions; - std::tuple - row; + std::tuple row; while (stream >> row) { - solutions.emplace_back(get<0>(row), get<1>(row), get<2>(row), get<3>(row), get<4>(row), get<5>(row), - get<6>(row), get<7>(row), get<8>(row), get<9>(row)); + solutions.emplace_back(get<0>(row), get<1>(row), + get<2>(row), get<3>(row), + get<4>(row), get<5>(row), + get<6>(row), get<7>(row), + get<8>(row), get<9>(row)); } stream.complete(); + manager->freeConnection(c); return solutions; } catch (...) { @@ -90,22 +112,27 @@ std::vector SolutionRepository::getSolutionsByTaskIdAndSenderId(size_t } } + std::vector SolutionRepository::getSolutionsByTaskIdAndLanguage(size_t task_id, std::string lang) { try { auto c = manager->connection(); std::string sql = - (boost::format("SELECT * FROM solutions WHERE task_id='%s' AND language='%s'") % task_id % lang).str(); + (boost::format("SELECT * FROM solutions WHERE" + " task_id='%s' AND language='%s'") % task_id % lang).str(); nontransaction n(*c); auto stream = stream_from::query(n, sql); std::vector solutions; - std::tuple - row; + std::tuple row; while (stream >> row) { - solutions.emplace_back(get<0>(row), get<1>(row), get<2>(row), get<3>(row), get<4>(row), get<5>(row), - get<6>(row), get<7>(row), get<8>(row), get<9>(row)); + solutions.emplace_back(get<0>(row), get<1>(row), + get<2>(row), get<3>(row), + get<4>(row), get<5>(row), + get<6>(row), get<7>(row), + get<8>(row), get<9>(row)); } stream.complete(); + manager->freeConnection(c); return solutions; } catch (...) { @@ -113,12 +140,16 @@ std::vector SolutionRepository::getSolutionsByTaskIdAndLanguage(size_t } } + std::optional SolutionRepository::getOriginalSolution(size_t id) { try { auto c = manager->connection(); - std::string sql = "SELECT * FROM solutions WHERE original_solution_id=" + std::to_string(id); + + std::string sql = "SELECT * FROM solutions WHERE" + " original_solution_id=" + std::to_string(id); nontransaction n(*c); result r(n.exec(sql)); + manager->freeConnection(c); if (r.empty()) return std::nullopt; return makeSolution(r.begin()); @@ -127,21 +158,24 @@ std::optional SolutionRepository::getOriginalSolution(size_t id) { } } + size_t SolutionRepository::storeSolution(Solution solution) { try { auto c = manager->connection(); - std::string sql = - (boost::format("INSERT INTO solutions (send_date,sender_id, source, task_id, result, tokens, " - "astTree, original_solution_id, language) " - "VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') RETURNING id; ") % - solution.getSendDate() % solution.getSenderId() % solution.getSource() % solution.getTaskId() % - solution.getResult() % solution.getTokens() % solution.getAstTree() % solution.getOrigSolution() % - solution.getLanguage()) - .str(); + std::string sql = (boost::format( + "INSERT INTO solutions (send_date,sender_id, source, task_id, result, tokens, " + "astTree, original_solution_id, language) " + "VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') RETURNING id; ") % + solution.getSendDate() % solution.getSenderId() % + solution.getSource() % solution.getTaskId() % + solution.getResult() % solution.getTokens() % + solution.getAstTree() % solution.getOrigSolution() % + solution.getLanguage()).str(); work w(*c); row r = (w.exec1(sql)); w.commit(); + manager->freeConnection(c); return r["id"].as(); } catch (...) { @@ -149,40 +183,49 @@ size_t SolutionRepository::storeSolution(Solution solution) { } } + void SolutionRepository::updateSolution(Solution solution) { try { auto c = manager->connection(); - std::string sql = (boost::format("UPDATE solutions SET send_date = '%s', sender_id = '%s', source = '%s'," - " task_id = '%s', result = '%s', tokens = '%s', astTree = '%s', " - "original_solution_id = '%s', language = '%s';") % - solution.getSendDate() % solution.getSenderId() % solution.getSource() % - solution.getTaskId() % solution.getResult() % solution.getTokens() % solution.getAstTree() % - solution.getOrigSolution() % solution.getLanguage()) - .str(); + std::string sql = (boost::format( + "UPDATE solutions SET send_date = '%s', sender_id = '%s', source = '%s'," + " task_id = '%s', result = '%s', tokens = '%s', astTree = '%s', " + "original_solution_id = '%s', language = '%s';") % + solution.getSendDate() % solution.getSenderId() % + solution.getSource() % solution.getTaskId() % + solution.getResult() % solution.getTokens() % + solution.getAstTree() % solution.getOrigSolution() % + solution.getLanguage()).str(); work w(*c); w.exec(sql); + manager->freeConnection(c); } catch (...) { throw; } } + void SolutionRepository::deleteSolutionById(size_t id) { try { auto c = manager->connection(); + std::string sql = "DELETE FROM solutions WHERE id=" + std::to_string(id); work w(*c); w.exec(sql); w.commit(); + manager->freeConnection(c); } catch (...) { throw; } } + void SolutionRepository::deleteSolution(Solution solution) { deleteSolutionById(solution.getId()); } + Solution SolutionRepository::makeSolution(const result::const_iterator &c) { return {c.at(c.column_number("id")).as(), c.at(c.column_number("send_date")).as(), @@ -195,5 +238,3 @@ Solution SolutionRepository::makeSolution(const result::const_iterator &c) { c.at(c.column_number("original_solution_id")).as(), c.at(c.column_number("language")).as()}; } - -SolutionRepository::SolutionRepository() { manager = std::make_shared(); } diff --git a/server/internal/repository/src/TaskRepository.cpp b/server/internal/repository/src/TaskRepository.cpp index 813f009daac8e07b4ce588805f9a65fb16666bed..07eef201fee12d83442247dc59c261d444d7128a 100644 --- a/server/internal/repository/src/TaskRepository.cpp +++ b/server/internal/repository/src/TaskRepository.cpp @@ -1,17 +1,21 @@ -#include "TaskRepository.hpp" - #include #include -#include +#include "TaskRepository.hpp" #include "Task.hpp" + +TaskRepository::TaskRepository() { manager = std::make_shared(); } + + std::optional TaskRepository::getTaskById(size_t id) { try { auto c = manager->connection(); + std::string sql = "SELECT * FROM tasks WHERE id=" + std::to_string(id); nontransaction n(*c); result r(n.exec(sql)); + manager->freeConnection(c); if (r.empty()) { return std::nullopt; @@ -22,18 +26,22 @@ std::optional TaskRepository::getTaskById(size_t id) { } } + std::vector TaskRepository::getAllTasks() { try { auto c = manager->connection(); + std::string sql = "SELECT * FROM tasks"; nontransaction n(*c); auto stream = stream_from::query(n, sql); std::vector tasks; std::tuple row; while (stream >> row) { - tasks.emplace_back(get<0>(row), get<1>(row), get<2>(row), get<3>(row)); + tasks.emplace_back(get<0>(row), get<1>(row), + get<2>(row), get<3>(row)); } stream.complete(); + manager->freeConnection(c); return tasks; } catch (...) { @@ -41,30 +49,37 @@ std::vector TaskRepository::getAllTasks() { } } + void TaskRepository::updateTask(const Task &task) { try { auto c = manager->connection(); - std::string sql = (boost::format("UPDATE tasks SET description = '%s', treshold = '%s', name = '%s';") % - task.getDescription() % task.getTreshhold() % task.getName()) - .str(); + + std::string sql = (boost::format( + "UPDATE tasks SET description = '%s', treshold = '%s', name = '%s';") % + task.getDescription() % task.getTreshhold() % task.getName()).str(); work w(*c); w.exec(sql); + manager->freeConnection(c); } catch (...) { throw; } } + size_t TaskRepository::storeTask(Task task) { try { auto c = manager->connection(); - std::string sql = (boost::format("INSERT INTO tasks (description, treshold, name) " - "VALUES ('%s', '%s', '%s') RETURNING id; ") % - task.getDescription() % task.getTreshhold() % task.getName()) - .str(); + + std::string sql = (boost::format( + "INSERT INTO tasks (description, treshold, name) " + "VALUES ('%s', '%s', '%s') RETURNING id; ") % + task.getDescription() % task.getTreshhold() % + task.getName()).str(); work w(*c); row r = w.exec1(sql); w.commit(); + manager->freeConnection(c); return r["id"].as(); } catch (...) { @@ -72,24 +87,29 @@ size_t TaskRepository::storeTask(Task task) { } } + void TaskRepository::deleteTask(Task task) { deleteTaskById(task.getId()); } + void TaskRepository::deleteTaskById(size_t task_id) { try { auto c = manager->connection(); + std::string sql = "DELETE FROM tasks WHERE id=" + std::to_string(task_id); work w(*c); w.exec(sql); w.commit(); + manager->freeConnection(c); } catch (...) { throw; } } + Task TaskRepository::makeTask(const result::const_iterator &c) { - return {c.at(c.column_number("id")).as(), c.at(c.column_number("description")).as(), - c.at(c.column_number("treshold")).as(), c.at(c.column_number("name")).as()}; + return {c.at(c.column_number("id")).as(), + c.at(c.column_number("description")).as(), + c.at(c.column_number("treshold")).as(), + c.at(c.column_number("name")).as()}; } - -TaskRepository::TaskRepository() { manager = std::make_shared(); } diff --git a/server/internal/repository/src/UserRepository.cpp b/server/internal/repository/src/UserRepository.cpp index 4d647b97e7474e181c1be8c415c7691b73a60489..689769e232b11572ce23ce4c7dac8d2eb04ac4aa 100644 --- a/server/internal/repository/src/UserRepository.cpp +++ b/server/internal/repository/src/UserRepository.cpp @@ -1,18 +1,21 @@ - -#include "UserRepository.hpp" - #include #include +#include "UserRepository.hpp" #include "User.hpp" #include "dbManager.hpp" +UserRepository::UserRepository() { manager = std::make_shared(); } + + std::optional UserRepository::getUserById(size_t id) { try { auto c = manager->connection(); + std::string sql = "SELECT * FROM Users WHERE id=" + std::to_string(id); nontransaction n(*c); result r(n.exec(sql)); + manager->freeConnection(c); if (r.empty()) return std::nullopt; return makeUser(r.begin()); @@ -21,12 +24,17 @@ std::optional UserRepository::getUserById(size_t id) { } } + std::optional UserRepository::getUserByLogin(std::string login) { try { auto c = manager->connection(); - std::string sql = (boost::format("SELECT * FROM Users WHERE login= '%s'") % login).str(); + + std::string sql = (boost::format( + "SELECT * FROM Users" + " WHERE login= '%s'") % login).str(); nontransaction n(*c); result r(n.exec(sql)); + manager->freeConnection(c); if (r.empty()) return std::nullopt; return makeUser(r.begin()); @@ -35,17 +43,19 @@ std::optional UserRepository::getUserByLogin(std::string login) { } } + size_t UserRepository::makeUser(User user) { try { auto c = manager->connection(); - std::string sql = (boost::format("INSERT INTO users (login,password,username) " - "VALUES ('%s', '%s', '%s') RETURNING id; ") % - user.getLogin() % user.getPassword() % user.getUsername()) - .str(); + std::string sql = (boost::format( + "INSERT INTO users (login,password,username) " + "VALUES ('%s', '%s', '%s') RETURNING id; ") % + user.getLogin() % user.getPassword() % user.getUsername()).str(); work w(*c); row r = w.exec1(sql); w.commit(); + manager->freeConnection(c); return r["id"].as(); } catch (...) { @@ -53,33 +63,41 @@ size_t UserRepository::makeUser(User user) { } } + void UserRepository::deleteByUserId(size_t user_id) { try { auto c = manager->connection(); + std::string sql = "DELETE FROM Users WHERE id=" + std::to_string(user_id); work w(*c); w.exec(sql); w.commit(); + manager->freeConnection(c); } catch (...) { throw; } } + void UserRepository::deleteUser(User user) { deleteByUserId(user.getId()); } + std::vector UserRepository::getAllUsers() { try { auto c = manager->connection(); + std::string sql = "SELECT * FROM Users"; nontransaction n(*c); auto stream = stream_from::query(n, sql); std::vector users; std::tuple row; while (stream >> row) { - users.emplace_back(get<0>(row), get<1>(row), get<2>(row), get<3>(row)); + users.emplace_back(get<0>(row), get<1>(row), + get<2>(row), get<3>(row)); } stream.complete(); + manager->freeConnection(c); return users; } catch (...) { @@ -87,24 +105,28 @@ std::vector UserRepository::getAllUsers() { } } -User UserRepository::makeUser(const result::const_iterator &c) { - return {c.at(c.column_number("id")).as(), c.at(c.column_number("login")).as(), - c.at(c.column_number("password")).as(), c.at(c.column_number("username")).as()}; -} - -UserRepository::UserRepository() { manager = std::make_shared(); } void UserRepository::update(User user) { try { auto c = manager->connection(); - std::string sql = (boost::format("UPDATE Users SET login = '%s', password = '%s', username = '%s';") % - user.getLogin() % user.getPassword() % user.getUsername()) - .str(); + std::string sql = (boost::format( + "UPDATE Users SET login = '%s', " + "password = '%s', username = '%s';") % + user.getLogin() % user.getPassword() % user.getUsername()).str(); work w(*c); w.exec(sql); + manager->freeConnection(c); } catch (...) { throw; } } + + +User UserRepository::makeUser(const result::const_iterator &c) { + return {c.at(c.column_number("id")).as(), + c.at(c.column_number("login")).as(), + c.at(c.column_number("password")).as(), + c.at(c.column_number("username")).as()}; +} diff --git a/server/internal/repository/tests/RepositoryTests.cpp b/server/internal/repository/tests/RepositoryTests.cpp index c14d237d4f995d6b9ae5c983c9ef7a971f28ba2b..6dd5280a52defea5dbd1c2a47727be10a88ee18b 100644 --- a/server/internal/repository/tests/RepositoryTests.cpp +++ b/server/internal/repository/tests/RepositoryTests.cpp @@ -21,68 +21,89 @@ TEST(UserRepository_CRUD_Test, CRUD) { if (new_user_opt) { new_user = new_user_opt.value(); } + EXPECT_EQ(user, new_user); + new_user.setUsername("new_test_user"); - EXPECT_NO_FATAL_FAILURE(rep.update(new_user)); + EXPECT_NO_FATAL_FAILURE(rep.update(new_user)); EXPECT_NO_FATAL_FAILURE(rep.deleteUser(new_user)); } + TEST(TaskRepository_CRUD_Test, CRUD) { TaskRepository rep; - Task task("test task", 0.5); + Task task("test task", 0.5, "name"); size_t id = rep.storeTask(task); + EXPECT_NO_FATAL_FAILURE(rep.getTaskById(1)); + task.setId(id); std::optional new_task_opt = rep.getTaskById(id); Task new_task; if (new_task_opt) new_task = new_task_opt.value(); + EXPECT_EQ(task, new_task); + new_task.setDescription("new_test_description"); + EXPECT_NO_FATAL_FAILURE(rep.updateTask(new_task)); EXPECT_NO_FATAL_FAILURE(rep.deleteTask(new_task)); } + TEST(SolutionRepository_CRUD_Test, CRUD) { SolutionRepository rep; - Solution solution("01.01.1970", 1, ":/C/Users", 1, "result", "tokens.txt", "tree.txt", 1); + Solution solution("01.01.1970", 1, ":/C/Users", 1, "result", "tokens.txt", "tree.txt", 1, "py"); size_t id = rep.storeSolution(solution); - EXPECT_NO_FATAL_FAILURE(rep.getSolutionById(163)); + + EXPECT_NO_FATAL_FAILURE(rep.getSolutionById(id)); + solution.setId(id); std::optional new_solution_opt = rep.getSolutionById(id); Solution new_solution; if (new_solution_opt) new_solution = new_solution_opt.value(); + EXPECT_EQ(solution, new_solution); + new_solution.setSource(":/D"); + EXPECT_NO_FATAL_FAILURE(rep.updateSolution(new_solution)); EXPECT_NO_FATAL_FAILURE(rep.deleteSolution(new_solution)); } + TEST(MetricRepository_CRUD_Test, CRUD) { MetricRepository rep; MetricStat metricStat(1, 0.8f, 0.9f, 0.89f, true, 0.85f); size_t id = rep.storeMetric(metricStat); + EXPECT_NO_FATAL_FAILURE(rep.getById(1)); + metricStat.setId(id); std::optional new_stat_opt = rep.getById(id); MetricStat new_stat; if (new_stat_opt) new_stat = new_stat_opt.value(); EXPECT_EQ(metricStat, new_stat); new_stat.setMeanRes(1); + EXPECT_NO_FATAL_FAILURE(rep.updateMetric(new_stat)); EXPECT_NO_FATAL_FAILURE(rep.deleteMetric(new_stat)); } + TEST(UserRepository_CRUD_Test, getAllUsers) { UserRepository rep; - std::vector v = {{"test@test.com", "test", "testuser"}, {"test2@test.com", "test2", "testuser2"}}; + std::vector v = {{"test@test.com", "test", "testuser"}, + {"test2@test.com", "test2", "testuser2"}}; EXPECT_NO_FATAL_FAILURE(rep.getAllUsers()); std::vector new_v = rep.getAllUsers(); EXPECT_EQ(v, new_v); } + TEST(UserRepository_CRUD_Test, loginLikeId) { UserRepository rep; User user("test@test.com", "test", "testuser"); @@ -95,31 +116,38 @@ TEST(UserRepository_CRUD_Test, loginLikeId) { EXPECT_NO_FATAL_FAILURE(rep.deleteUser(user)); } + TEST(SolutionRepository_CRUD_Test, CRUD_getSolutionsBySenderId) { SolutionRepository rep; - Solution solution1("01.01.1970", 1, ":/C/Users", 1, "result", "tokens.txt", "tree.txt", 1); - Solution solution2("01.01.1970", 1, "home/usr", 1, "result", "tokens.txt", "tree.txt", 1); + Solution solution1("01.01.1970", 1, ":/C/Users", 1, "result", "tokens.txt", "tree.txt", 1, "py"); + Solution solution2("01.01.1970", 1, "home/usr", 1, "result", "tokens.txt", "tree.txt", 1, "cpp"); size_t id1 = rep.storeSolution(solution1); solution1.setId(id1); + EXPECT_EQ(solution1, rep.getSolutionById(id1)); + size_t id2 = rep.storeSolution(solution2); solution2.setId(id2); + EXPECT_EQ(solution2, rep.getSolutionById(id2)); - std::vector v = {{id1, "01.01.1970", 1, ":/C/Users", 1, "result", "tokens.txt", "tree.txt", 1}, - {id2, "01.01.1970", 1, "home/usr", 1, "result", "tokens.txt", "tree.txt", 1}}; + + std::vector v = {{id1, "01.01.1970", 1, ":/C/Users", 1, "result", "tokens.txt", "tree.txt", 1, "py"}, + {id2, "01.01.1970", 1, "home/usr", 1, "result", "tokens.txt", "tree.txt", 1, "cpp"}}; std::vector new_v = rep.getSolutionsBySenderId(solution1.getSenderId()); + EXPECT_EQ(v, new_v); EXPECT_NO_FATAL_FAILURE(rep.deleteSolution(solution1)); EXPECT_NO_FATAL_FAILURE(rep.deleteSolution(solution2)); } + TEST(SolutionRepository_CRUD_Test, CRUD_getSolutionsByTaskId) { SolutionRepository rep; - Solution solution1("01.01.1970", 1, ":/C/Users", 1, "result", "tokens.txt", "tree.txt", 1); - Solution solution2("01.01.1970", 1, "home/usr", 1, "result", "tokens.txt", "tree.txt", 1); + Solution solution1("01.01.1970", 1, ":/C/Users", 1, "result", "tokens.txt", "tree.txt", 1, "py"); + Solution solution2("01.01.1970", 1, "home/usr", 1, "result", "tokens.txt", "tree.txt", 1, "cpp"); size_t id1 = rep.storeSolution(solution1); solution1.setId(id1); @@ -127,14 +155,54 @@ TEST(SolutionRepository_CRUD_Test, CRUD_getSolutionsByTaskId) { solution2.setId(id2); std::vector v = {solution1, solution2}; std::vector new_v = rep.getSolutionsByTaskId(solution1.getTaskId()); + + EXPECT_EQ(v, new_v); + EXPECT_NO_FATAL_FAILURE(rep.deleteSolution(solution1)); + EXPECT_NO_FATAL_FAILURE(rep.deleteSolution(solution2)); +} + + +TEST(SolutionRepository_CRUD_Test, CRUD_getSolutionsByTaskIdAndLanguage) { + SolutionRepository rep; + Solution solution1("01.01.1970", 1, ":/C/Users", 1, "result", "tokens.txt", "tree.txt", 1, "py"); + Solution solution2("01.01.1970", 1, "home/usr", 1, "result", "tokens.txt", "tree.txt", 1, "cpp"); + + size_t id1 = rep.storeSolution(solution1); + solution1.setId(id1); + size_t id2 = rep.storeSolution(solution2); + solution2.setId(id2); + std::vector new_v = rep.getSolutionsByTaskIdAndLanguage(1, "py"); + + EXPECT_EQ(solution1, new_v[0]); + EXPECT_NO_FATAL_FAILURE(rep.deleteSolution(solution1)); + EXPECT_NO_FATAL_FAILURE(rep.deleteSolution(solution2)); +} + + +TEST(SolutionRepository_CRUD_Test, CRUD_getSolutionsByTaskIdAndSenderId) { + SolutionRepository rep; + Solution solution1("01.01.1970", 1, ":/C/Users", 1, "result", "tokens.txt", "tree.txt", 1, "py"); + Solution solution2("01.01.1970", 1, "home/usr", 1, "other result", "tokens1.txt", "tree3.txt", 1, "cpp"); + Solution solution3("01.01.1971", 2, ":/C/Easter_egg", 1, "another result", "tokens2.txt", "tree1.txt", 1, "py"); + size_t id1 = rep.storeSolution(solution1); + solution1.setId(id1); + size_t id2 = rep.storeSolution(solution2); + solution2.setId(id2); + size_t id3 = rep.storeSolution(solution3); + solution2.setId(id3); + std::vector v = {solution1, solution2}; + std::vector new_v = rep.getSolutionsByTaskIdAndSenderId(1, 1); + EXPECT_EQ(v, new_v); EXPECT_NO_FATAL_FAILURE(rep.deleteSolution(solution1)); EXPECT_NO_FATAL_FAILURE(rep.deleteSolution(solution2)); + EXPECT_NO_FATAL_FAILURE(rep.deleteSolution(solution3)); } + TEST(SolutionRepository_CRUD_Test, tryToAddWithNotExistingTask) { SolutionRepository rep; - Solution solution("01.01.1970", 1, ":/C/Users", 100500, "result", "tokens.txt", "tree.txt", 1); + Solution solution("01.01.1970", 1, ":/C/Users", 100500, "result", "tokens.txt", "tree.txt", 1, "py"); try { rep.storeSolution(solution); } catch (pqxx::foreign_key_violation &e) { @@ -142,10 +210,11 @@ TEST(SolutionRepository_CRUD_Test, tryToAddWithNotExistingTask) { } } + TEST(SolutionRepository_CRUD_Test, tryToStoreWithNotExistingSender) { SolutionRepository rep; - Solution solution("01.01.1970", 100500, ":/C/Users", 100500, "result", "tokens.txt", "tree.txt", 1); + Solution solution("01.01.1970", 100500, ":/C/Users", 100500, "result", "tokens.txt", "tree.txt", 1, "cpp"); try { rep.storeSolution(solution); } catch (pqxx::foreign_key_violation &keyViolation) {